import { FC, useState, useEffect } from 'react';
import { useForm, FormProvider } from 'react-hook-form';
import { useQuery } from 'react-query';
import { useParams } from 'react-router-dom';

import CallIcon from '@material-hu/icons/material/Call';
import EmailIcon from '@material-hu/icons/material/Email';
import PersonIcon from '@material-hu/icons/material/Person';
import Box from '@material-hu/mui/Box';
import Card from '@material-hu/mui/Card';
import CardContent from '@material-hu/mui/CardContent';
import Container from '@material-hu/mui/Container';
import Divider from '@material-hu/mui/Divider';
import TextField from '@material-hu/mui/TextField';
import Typography from '@material-hu/mui/Typography';

import Button from '@material-hu/components/design-system/Buttons/Button';

import { EXTRA_FIELD_NAME } from 'src/constants/events';
import useGeneralError from 'src/hooks/useGeneralError';
import { useMobileLayout } from 'src/hooks/useMobileLayout';
import {
  getExtraFields,
  getEventData,
  getUserData,
  subscribeIntoWaitingList,
  submitRegistration,
  createQRCode,
  getFieldsCatalogues,
} from 'src/services/nemakEvents';
import {
  hasTshirt,
  hasRelativeInfo,
  hasTeamInfo,
  validateRelativesInfo,
  validateTeamInfo,
  processExtraFields,
  processArray,
  userExistsInSelected,
  getUserToAdd,
  updateTshirtSizeInList,
  getDefaultValues,
} from 'src/utils/events';

import AlertSnackbar from './components/AlertSnackbar';
import AlreadyEventRegistration from './components/AlreadyEventRegistration';
import ErrorMessage from './components/ErrorMessage';
import EventCardItem from './components/EventCardItem';
import ExhaustEventRegistration from './components/ExhaustEventRegistration';
import FieldRenderer from './components/FieldRendered';
import DropDownController from './components/formControls/DropDownController';
import { useTranslation } from './components/i18n';
import { eventsKeys } from './components/queries';
import SuccessEventRegistration from './components/SuccessEventRegistration';

export const FormEvent: FC = () => {
  const { formId, employeeId } = useParams();
  const showGeneralError = useGeneralError();

  useMobileLayout();

  const { data: formExtraFields, isLoading: isLoadingExtraFields } = useQuery(
    [eventsKeys.form.extraFields(formId)],
    () => getExtraFields(formId),
    {
      enabled: !!formId,
    },
  );

  const { data: formData, isLoading: isLoadingFormData } = useQuery(
    [eventsKeys.form.detail(formId)],
    () => getEventData(formId),
    {
      enabled: !!formId,
    },
  );

  const { data: userData, isLoading: isLoadingUserData } = useQuery(
    [eventsKeys.employee.detail(employeeId)],
    () => getUserData(employeeId),
    {
      enabled: !!employeeId,
    },
  );

  const userInfo = userData?.data?.EmployeeBasics;
  const realtivesInfoData = userData?.data?.Relatives;

  const realtivesInfo = realtivesInfoData?.map(item => {
    return {
      ...item,
      TshirtSize: null,
      TshirtSizeDisplay: null,
    };
  });

  const { t } = useTranslation();

  const [guestsNumber, setGuestsNumber] = useState(null);
  const [confirmationCode, setConfirmationCode] = useState(null);
  const [statusCode, setStatusCode] = useState(null);
  const [hasWaitingList, setHasWaitingList] = useState(false);
  const [waitingListCode, setWaitingListCode] = useState(null);
  const [dropdownValues, setDropdownValues] = useState<any>([]);
  const [selectedRelatives, setSelectedRelatives] = useState([]);
  const [selectedUsers, setSelectedUsers] = useState([]);
  const [selectedVolunteers, setSelectedVolunteers] = useState([]);
  const [openInvalidEmployee, setOpenInvalidEmployee] = useState(false);
  const [openExistEmployee, setOpenExistEmployee] = useState(false);
  const [qrImage, setQrImage] = useState(null);
  const [errorMessage, setErrorMessage] = useState(null);

  const addItemToDropdownMap = (key, value) => {
    setDropdownValues(prevMap => {
      return { ...prevMap, [key]: value };
    });
  };

  const form = useForm({
    defaultValues: getDefaultValues(formExtraFields),
  });

  const {
    handleSubmit,
    formState: { errors },
  } = form;

  useEffect(() => {
    const renderDropdown = async field => {
      try {
        const isTshirt =
          field.FieldName === EXTRA_FIELD_NAME.TEAM_SIZE ||
          field.FieldName === EXTRA_FIELD_NAME.GUEST_SIZE;
        const { data } = await getFieldsCatalogues(
          isTshirt ? 'TshirtSize' : field.FieldName,
        );
        addItemToDropdownMap(field.FieldName, data);
      } catch (error) {
        showGeneralError(error);
      }
    };

    if (formExtraFields) {
      formExtraFields?.data?.forEach(field => renderDropdown(field));
    }
  }, [formExtraFields]);

  const isSelected = relative =>
    selectedRelatives.some(
      r =>
        r.FirstName === relative.FirstName &&
        r.LastName === relative.LastName &&
        r.Age === relative.Age,
    );

  const handleCheckboxChange = (relative, isChecked) => {
    if (isChecked) {
      setSelectedRelatives([...selectedRelatives, relative]);
    } else {
      setSelectedRelatives(
        selectedRelatives.filter(
          r =>
            r.FirstName !== relative.FirstName ||
            r.LastName !== relative.LastName ||
            r.Age !== relative.Age,
        ),
      );
    }
  };

  const handleAddRelativeSize = (event, relative) => {
    const newValue = event.target.value;
    const updatedRelatives = updateTshirtSizeInList(
      selectedRelatives,
      relative,
      newValue,
      dropdownValues.GuestsTshirtSizes,
    );
    setSelectedRelatives(updatedRelatives);
  };

  const handleAddTeamSize = (event, index) => {
    const newValue = event.target.value;
    const userToUpdate = selectedUsers[index];
    const updatedUsers = updateTshirtSizeInList(
      selectedUsers,
      userToUpdate,
      newValue,
      dropdownValues.TeamTshirtSize,
    );
    setSelectedRelatives(updatedUsers);
  };

  const isTshirt = hasTshirt(formExtraFields?.data);
  const isRelativeInfo = hasRelativeInfo(formExtraFields?.data);
  const isTeamInfo = hasTeamInfo(formExtraFields?.data);

  const validateForm = () => {
    let newErrorMessage = null;

    if (isRelativeInfo && realtivesInfo?.length > 0) {
      newErrorMessage = validateRelativesInfo(selectedRelatives, isTshirt);
    }

    if (!newErrorMessage && isTeamInfo) {
      newErrorMessage = validateTeamInfo(selectedUsers, isTshirt);
    }

    setErrorMessage(newErrorMessage);
    return newErrorMessage;
  };

  const submitForm = async (data?: any) => {
    const error = validateForm();

    if (!error) {
      const extraFieldsProcessed = processExtraFields(
        data,
        formExtraFields?.data?.StatusCode,
      );
      const selectedRelativesProcessed =
        selectedRelatives.length > 0
          ? JSON.stringify({ children: processArray(selectedRelatives) })
          : '';
      const selectedUsersProcessed =
        selectedUsers.length > 0
          ? JSON.stringify({ team: processArray(selectedUsers) })
          : '';
      const selectedVolunteersProcessed =
        selectedVolunteers.length > 0
          ? JSON.stringify({ volunteers: processArray(selectedVolunteers) })
          : '';

      try {
        const response = await submitRegistration(
          formId,
          employeeId,
          userInfo,
          data.guestsNumber,
          extraFieldsProcessed,
          selectedRelativesProcessed,
          selectedUsersProcessed,
          selectedVolunteersProcessed,
        );

        if (response?.status === 200) {
          setStatusCode(response.data.StatusCode);
          setGuestsNumber(data.guestsNumber);
          if (response.data.StatusCode === '0') {
            const qr = await createQRCode(response.data.ExtraCode);
            setConfirmationCode(response.data.ExtraCode);
            setQrImage(qr.data);
          }
        }
      } catch (submitError) {
        showGeneralError(submitError);
      }
    }
  };

  const submitWaitingListForm = async () => {
    try {
      const response = await subscribeIntoWaitingList(
        formId,
        employeeId,
        userInfo,
        guestsNumber,
      );
      if (response?.status === 200) {
        setHasWaitingList(true);
        if (response.data.StatusCode === '0') {
          setWaitingListCode(response.data.ExtraCode);
        }
      }
    } catch (submitWaitingError) {
      showGeneralError(submitWaitingError);
    }
  };

  const onSubmit = data => submitForm(data);

  const maxGuestsArray = Array.from(
    { length: formData?.data?.MaxGuests },
    (_, i) => i + 1,
  );

  const handleFetchUser = async id => {
    try {
      const response = await getUserData(id);
      const fetchedEmployeeId = response.data.EmployeeBasics.PersonIdExternal;
      if (response.data.Logger) {
        setOpenInvalidEmployee(true);
      } else if (userExistsInSelected(fetchedEmployeeId, selectedUsers)) {
        setOpenExistEmployee(true);
      } else {
        const userToAdd = getUserToAdd(response.data.EmployeeBasics);
        setSelectedUsers([...selectedUsers, userToAdd]);
      }
    } catch (error) {
      showGeneralError(error);
    }
  };

  const handleAddVolunteer = name =>
    setSelectedVolunteers([...selectedVolunteers, { VolunteerName: name }]);

  const handleDeleteUser = id => {
    const updatedUsers = selectedUsers.filter(
      user => user.EmployeeNumber !== id,
    );
    setSelectedUsers(updatedUsers);
  };

  const handleDeleteVolunteer = index => {
    const updatedVolunteers = [...selectedVolunteers];
    updatedVolunteers.splice(index, 1);
    setSelectedVolunteers(updatedVolunteers);
  };

  if (
    !statusCode &&
    !isLoadingExtraFields &&
    !isLoadingFormData &&
    !isLoadingUserData
  ) {
    return (
      <Container
        sx={{ py: 4 }}
        maxWidth="sm"
      >
        <FormProvider {...form}>
          <form onSubmit={handleSubmit(onSubmit)}>
            <Card sx={{ width: '100%' }}>
              <Box sx={{ p: 2 }}>
                <Typography
                  color="textPrimary"
                  variant="h5"
                  component="h1"
                >
                  {t('GENERAL_INFORMATION')}
                </Typography>
              </Box>
              <Divider />
              <CardContent sx={{ p: 2 }}>
                {userInfo.FirstName !== '' && userInfo.LastName !== '' && (
                  <EventCardItem
                    Icon={PersonIcon}
                    i18nKey="EMPLOYEE_NAME"
                    transValues={{
                      employeeName: `${userInfo.FirstName} ${userInfo.LastName}`,
                    }}
                  />
                )}
                {userInfo.EmailAddress !== '' && (
                  <EventCardItem
                    Icon={EmailIcon}
                    i18nKey="EMPLOYEE_EMAIL"
                    transValues={{ employeeEmail: userInfo.EmailAddress }}
                  />
                )}
                {userInfo.PhoneNumber && (
                  <EventCardItem
                    Icon={CallIcon}
                    i18nKey="EMPLOYEE_PHONE"
                    transValues={{ employeePhone: userInfo.PhoneNumber }}
                  />
                )}
              </CardContent>
            </Card>
            <Card sx={{ width: '100%', mt: 2 }}>
              <Box sx={{ p: 2 }}>
                <Typography
                  color="textPrimary"
                  variant="h5"
                  component="h1"
                >
                  {t('FORM_INFORMATION')}
                </Typography>
              </Box>
              <Divider />
              <CardContent sx={{ p: 2 }}>
                <TextField
                  label={t('EVENT_NAME_LABEL')}
                  value={formData?.data?.Name}
                  sx={{ mt: 2, mb: 1 }}
                  fullWidth
                  disabled
                />
                <DropDownController
                  name="guestsNumber"
                  label={t('EVENT_GUESTS_LABEL')}
                  dropdownValues={maxGuestsArray}
                />
                {!formExtraFields?.data?.StatusCode && (
                  <>
                    {formExtraFields?.data?.map(field => (
                      <FieldRenderer
                        key={field.FieldName}
                        field={field}
                        dropdownValues={dropdownValues}
                        realtivesInfo={realtivesInfo}
                        isTshirt={isTshirt}
                        handleAddRelativeSize={handleAddRelativeSize}
                        handleCheckboxChange={handleCheckboxChange}
                        isSelected={isSelected}
                        handleFetchUser={handleFetchUser}
                        selectedUsers={selectedUsers}
                        handleAddTeamSize={handleAddTeamSize}
                        handleDeleteUser={handleDeleteUser}
                        handleAddVolunteer={handleAddVolunteer}
                        selectedVolunteers={selectedVolunteers}
                        handleDeleteVolunteer={handleDeleteVolunteer}
                      />
                    ))}
                  </>
                )}
                <AlertSnackbar
                  open={openInvalidEmployee}
                  onClose={() => setOpenInvalidEmployee(false)}
                  message={t('NOT_EMPLOYEE_FOUND')}
                />
                <AlertSnackbar
                  open={openExistEmployee}
                  onClose={() => setOpenExistEmployee(false)}
                  message={t('EXISTS_EMPLOYEE')}
                  alertType="info"
                />
              </CardContent>
              {Object.keys(errors).length > 0 && (
                <ErrorMessage message={t('REQUIRED_FIELDS_ALERT')} />
              )}
              {errorMessage && <ErrorMessage message={t(errorMessage)} />}
            </Card>
            <Box
              sx={{
                display: 'flex',
                width: '100%',
                justifyContent: 'flex-end',
                mt: 2,
              }}
            >
              <Button
                variant="contained"
                type="submit"
              >
                {t('REGISTER_EVENT')}
              </Button>
            </Box>
          </form>
        </FormProvider>
      </Container>
    );
  } else if (statusCode === 1 || statusCode === '1') {
    return <AlreadyEventRegistration />;
  } else if (statusCode === 0 || statusCode === '0') {
    return (
      <SuccessEventRegistration
        confirmationCode={confirmationCode}
        eventName={formData?.data?.Name}
        qrImage={qrImage}
      />
    );
  } else if (statusCode === 2 || statusCode === '2') {
    return (
      <ExhaustEventRegistration
        waitingListCode={waitingListCode}
        hasWaitingList={hasWaitingList}
        eventName={formData?.data?.Name}
        onClick={submitWaitingListForm}
      />
    );
  }
};

export default FormEvent;
