'use client';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Grid, Button, IconButton } from '@mui/material';
import type { FormFieldType } from '@/shared/types/common';
import FormField from '@/shared/components/form/form-field';
import ScheduleTable from '@/shared/components/form/schedule-table';
import FontAwesome from '@/shared/components/fontawesome';
import { faAnglesDown, faAnglesUp, faSquareMinus } from '@fortawesome/free-solid-svg-icons';
import { Box } from '@mui/system';
import { centerFlexColumn, iconButtonStyles } from '@/shared/theme/css';
import { pxToRem } from '@/shared/theme/typography';
import { useMultipleFields } from '@/hooks/use-multiple-fields';
import DuplicableField from '@/shared/components/form/duplicable-field';
import { getIn } from 'formik';
import { SensTrip, WeekType, type Representative } from '@/shared/types/passenger';
import { type Address, AddressType, dayOfWeekLabelsFr } from '@/shared/types/establishment';
import ConditionalComponent from '@/shared/components/table/ConditionalComponent';
import CustomTooltip from '@/shared/components/tooltips/tooltip-custom';
import { disabledFields, type RepresentantFormProps } from '../../../types/representant-form.types';
import { useRepresentantForm } from './hooks/use-representant-form';
import {
  contactFormFields,
  contactsFormFields,
  mainRepresentantformFields,
} from '../../../utils/form-fields-representative';

const typeMapLocal = {
  mobilePhoneNumbers: 'mobile',
  landlinePhoneNumbers: 'fixe',
  assignedPersonNames: 'personne',
} as const;

export default function UnifiedRepresentantForm(props: RepresentantFormProps) {
  const {
    data,
    mode,
    isReadOnly,
    onChange,
    tabIndex,
    variant,
    handleTabClose,
    isUsagerAttachedToAmendment = true,
    trajectorySchedules,
    representatives,
    tabId,
  } = props;
  const [isReduced, setIsReduced] = useState(true);
  const isEditMode = mode === 'edit';

  const {
    circuitOptions,
    selectedDays,
    formikPath,
    formData,
    getCircuits,
    updateSelectedDays,
    getFieldError,
    formik,
    shouldDisableField,
    shouldDisableSchedules,
  } = useRepresentantForm({ data, variant, tabIndex, onChange, mode });

  const { fields, handleAdd, handleDelete, handleChange } = useMultipleFields({
    initialValues: {
      mobile: formData.mobile,
      fixe: formData.fixe,
      personne: formData.personne,
    },
    onChange: (type, newValues) => {
      const updatedData: Partial<Representative> = {
        ...data,
        contacts: [
          {
            ...data.contacts[0],
            [type === 'mobile'
              ? 'mobilePhoneNumbers'
              : type === 'fixe'
                ? 'landlinePhoneNumbers'
                : 'assignedPersonNames']: newValues,
          },
        ],
      };
      onChange(updatedData);
    },
    isReadOnly,
  });

  const handleSelectionChange = useCallback(
    ({
      week,
      day,
      type,
      checked,
    }: {
      week: 'pair' | 'impair';
      day: string;
      type: 'all' | 'ret';
      checked: boolean;
    }) => {
      const uncheckedChoices: [
        {
          week: string;
          day: string;
          type: string;
        },
      ] = [
        {
          week: 'init',
          day: 'init',
          type: 'init',
        },
      ];
      if (representatives && tabId !== undefined) {
        const otherRepresentatives = representatives.filter((_, index) => index !== tabId);

        otherRepresentatives.forEach((otherRep) => {
          otherRep.transportSchedulesRepresentative.forEach((trasnportSchedule) => {
            trasnportSchedule.dayScheduleRepresentative.forEach((representantSchedule) => {
              const day = dayOfWeekLabelsFr[representantSchedule.dayOfWeek].toLowerCase();
              const type = representantSchedule.sens === SensTrip.DEPARTURE ? 'all' : 'ret';
              const week = trasnportSchedule.weekType === WeekType.EVEN ? 'pair' : 'impair';
              uncheckedChoices.push({
                day,
                type,
                week,
              });
            });
          });
        });
      }


      if (isUsagerAttachedToAmendment && isEditMode) {
        return;
      }
      if (
        (!isReadOnly && !shouldDisableSchedules(isEditMode)) ||
        (!isUsagerAttachedToAmendment && isEditMode)
      ) {
        const oppositeWeek = week === 'pair' ? 'impair' : 'pair';
        const newSchedule = { ...selectedDays };

        if (checked) {
          const periods: ('all' | 'ret')[] = ['all', 'ret'];
          periods.forEach((p) => {
            const blocked = uncheckedChoices?.some(
              (choice) => choice.week === week && choice.day === day && choice.type === p
            );
            const blockedOpposite = uncheckedChoices?.some(
              (choice) => choice.week === oppositeWeek && choice.day === day && choice.type === p
            );
            if (!blocked) {
              newSchedule[week] = {
                ...newSchedule[week],
                [day]: {
                  ...newSchedule[week]?.[day],
                  [p]: true,
                },
              };
            }
            if (!blockedOpposite) {
              newSchedule[oppositeWeek] = {
                ...newSchedule[oppositeWeek],
                [day]: {
                  ...newSchedule[oppositeWeek]?.[day],
                  [p]: true,
                },
              };
            }
          });
        } else {
          newSchedule[week] = {
            ...newSchedule[week],
            [day]: {
              ...newSchedule[week]?.[day],
              [type]: false,
            },
          };
        }

        updateSelectedDays(newSchedule);
      }
    },
    [isReadOnly, selectedDays, updateSelectedDays, shouldDisableSchedules, isEditMode]
  );

  const handleSelectionMultiple = useCallback(
    ({ week, checked }: { week: 'pair' | 'impair'; checked: boolean }) => {
      if (isUsagerAttachedToAmendment && isEditMode) {
        return;
      }
      if (
        (!isReadOnly && !shouldDisableSchedules(isEditMode)) ||
        (!isUsagerAttachedToAmendment && isEditMode)
      ) {
        const newSchedule = { ...selectedDays };

        ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi'].forEach((day) => {
          const periods: ('all' | 'ret')[] = ['all', 'ret'];
          periods.forEach((p) => {
            newSchedule[week] = {
              ...newSchedule[week],
              [day]: {
                ...newSchedule[week]?.[day],
                [p]: checked,
              },
            };
          });
        });

        updateSelectedDays(newSchedule);
      }
    },
    [isReadOnly, selectedDays, updateSelectedDays, shouldDisableSchedules, isEditMode]
  );

  const handleFieldChange = useCallback(
    (name: string, value: any) => {
      if (name === 'addresses' || name === 'pickupAddress') {
        const addressType =
          name === 'pickupAddress' ? AddressType.PICKUP : AddressType.REPRESENTATIVE;
        const addressData: Address = {
          additionalAddress: value.address || '',
          latitude: value.lat || 0,
          longitude: value.lng || 0,
          city: value.city || '',
          zipCode: value.zipCode || '',
          country: value.country || '',
          addressType: addressType,
        };
        const updatedAddresses = (data.addresses || []).reduce<Address[]>(
          (acc, currentAddr) => {
            if (currentAddr.addressType !== addressType) {
              acc.push(currentAddr);
            }
            return acc;
          },
          [addressData]
        );
        const updatedData: Partial<Representative> = {
          ...data,
          addresses: updatedAddresses,
        };
        onChange(updatedData);
      } else {
        const updatedData: Partial<Representative> = {
          ...data,
          [name]: value,
        };
        onChange(updatedData);
      }
    },
    [data, onChange]
  );

  const renderField = useCallback(
    (field: FormFieldType<any>) => {
      const fieldName = field.name as string;
      const error = getFieldError(fieldName);
      return (
        <FormField
          field={field}
          value={
            field.name === 'circuitId'
              ? formData.circuitId
              : field.name === 'addresses'
                ? formData.additionalAddress
                : field.name === 'pickupAddress'
                  ? formData.pickupAddress
                  : (formData as any)[fieldName]
          }
          onChange={handleFieldChange}
          error={error}
          isReadOnly={
            shouldDisableField(
              fieldName,
              isEditMode,
              isEditMode && (isUsagerAttachedToAmendment as boolean) ? disabledFields : []
            ) || isReadOnly
          }
          isDrawerElement={true}
          onBlur={() => formik.setFieldTouched(`${formikPath}[${tabIndex}].${fieldName}`, true)}
        />
      );
    },
    [
      getFieldError,
      formData,
      handleFieldChange,
      isReadOnly,
      formik,
      tabIndex,
      isEditMode,
      formikPath,
    ]
  );

  const memoizedFormFields = useMemo(() => {
    if (isReduced) {
      return (
        <>
          <Grid item xs={12} sm={4} sx={centerFlexColumn} key="type">
            {renderField(mainRepresentantformFields.find((f) => f.name === 'type')!)}
          </Grid>
          <Grid item xs={12} sm={8} sx={centerFlexColumn} key="civility">
            {renderField(mainRepresentantformFields.find((f) => f.name === 'civility')!)}
          </Grid>
        </>
      );
    }
    return (
      <>
        {mainRepresentantformFields.map((field) => (
          <Grid
            item
            xs={12}
            sm={field.name === 'civility' ? 8 : 4}
            sx={centerFlexColumn}
            key={field.name}
          >
            {renderField(field)}
          </Grid>
        ))}
      </>
    );
  }, [renderField, isReduced]);

  const renderPhoneFields = useMemo(() => {
    return ['mobilePhoneNumbers', 'landlinePhoneNumbers', 'assignedPersonNames'].map((type) => {
      const fieldType = typeMapLocal[type as keyof typeof typeMapLocal];
      const numbers = fields[fieldType] || [];
      const field = contactsFormFields.find((f) => f.name === type);
      return numbers.map((number: string, index: number) => {
        const fieldPath = `${formikPath}[${tabIndex}].contacts[0].${type}[${index}]`;
        const error =
          getIn(formik.errors, fieldPath) && getIn(formik.touched, fieldPath)
            ? String(getIn(formik.errors, fieldPath))
            : undefined;
        return (
          <DuplicableField
            key={`${type}-${index}`}
            fieldType={fieldType}
            field={field!}
            index={index}
            value={number}
            isReadOnly={isReadOnly}
            onChange={handleChange}
            onAdd={handleAdd}
            onDelete={handleDelete}
            sx={{ display: 'flex', flexDirection: 'column' }}
            formData={formData}
            error={error}
            onBlur={() => formik.setFieldTouched(fieldPath, true)}
          />
        );
      });
    });
  }, [
    fields,
    isReadOnly,
    handleAdd,
    handleDelete,
    handleChange,
    formik,
    formData,
    tabIndex,
    formikPath,
  ]);

  const phoneFieldsLine = useMemo(() => {
    const firstMobileField = renderPhoneFields.slice(0, 1);
    const firstFixeField = renderPhoneFields.slice(1, 2);
    const firstPersonneField = renderPhoneFields.slice(2, 3);

    return (
      <>
        {firstMobileField}
        {firstFixeField}
        {firstPersonneField}
      </>
    );
  }, [renderPhoneFields]);

  const finalFieldsLine = useMemo(() => {
    const pickupAddressField = contactFormFields(circuitOptions, getCircuits)[2];
    const lastTwoFields = contactFormFields(circuitOptions, getCircuits).slice(-2);

    return (
      <>
        <Grid item xs={12} sm={4} sx={centerFlexColumn} key={pickupAddressField.name}>
          {renderField(pickupAddressField)}
        </Grid>
        {lastTwoFields.map((field) => (
          <Grid item xs={12} sm={field.name === 'arrivalNotification' ? 4 : 4} key={field.name}>
            {renderField(field)}
          </Grid>
        ))}
      </>
    );
  }, [circuitOptions, renderField, getCircuits]);

  const emailCircuitLine = useMemo(() => {
    const emailField = contactFormFields(circuitOptions, getCircuits)[0];
    const circuitField = contactFormFields(circuitOptions, getCircuits)[1];

    return (
      <>
        <Grid item xs={12} sm={4} sx={centerFlexColumn} key={emailField.name}>
          {renderField(emailField)}
        </Grid>
        <Grid item xs={12} sm={4} sx={centerFlexColumn} key={circuitField.name}>
          {renderField(circuitField)}
        </Grid>
      </>
    );
  }, [circuitOptions, renderField, getCircuits]);

  const lastFormFields = useMemo(() => {
    const lastTwoFields = contactFormFields(circuitOptions, getCircuits).slice(-2);
    return (
      <>
        {lastTwoFields.map((field) => (
          <Grid item xs={12} sm={field.name === 'arrivalNotification' ? 6 : 4} key={field.name}>
            {renderField(field)}
          </Grid>
        ))}
      </>
    );
  }, [circuitOptions, renderField, getCircuits]);

  const handleToggleReduced = useCallback(() => {
    setIsReduced((prev) => !prev);
  }, []);

  const allFields = [
    ...mainRepresentantformFields,
    ...contactFormFields(circuitOptions, getCircuits),
  ];

  useEffect(() => {
    if (mode === 'add' && trajectorySchedules) {
      updateSelectedDays(trajectorySchedules);
    }
  }, [trajectorySchedules]);
  return (
    <Box
      sx={{
        width: '100%',
        mb: 2,
        height: isReduced ? '80px' : 'auto',
        overflow: isReduced ? 'hidden' : 'visible',
      }}
    >
      <Box sx={{ position: 'absolute', bottom: 0, right: 0 }}>
        <Button
          endIcon={<FontAwesome icon={isReduced ? faAnglesDown : faAnglesUp} width={12} />}
          onClick={handleToggleReduced}
          variant="text"
          sx={{
            textTransform: 'none',
            fontSize: pxToRem(13),
            '&:hover': {
              backgroundColor: 'transparent',
            },
          }}
        >
          {isReduced ? 'Voir plus' : 'Réduire détails'}
        </Button>
      </Box>

      <ConditionalComponent isValid={!isReadOnly && !isReduced}>
        <Box sx={{ display: 'flex', justifyContent: 'flex-end', mb: 1 }}>
          <CustomTooltip title="Supprimer Adresse" arrow>
            <IconButton sx={iconButtonStyles} onClick={(e) => handleTabClose(e, tabIndex)}>
              <FontAwesome icon={faSquareMinus} width={15} />
            </IconButton>
          </CustomTooltip>
        </Box>
      </ConditionalComponent>

      <Grid container spacing={2} sx={{ pt: 2 }}>
        {memoizedFormFields}

        {emailCircuitLine}

        <Grid container item spacing={2}>
          {phoneFieldsLine}
        </Grid>

        {renderPhoneFields.slice(3)}

        {finalFieldsLine}
      </Grid>
      <ScheduleTable
        onMultipleSelectionChange={handleSelectionMultiple}
        title="Trajets concernés"
        mode="checkbox"
        selectedDays={selectedDays}
        onSelectionChange={handleSelectionChange}
        isRepresentative={true}
      />
    </Box>
  );
}

export function RepresentantForm(
  props: Omit<RepresentantFormProps & { variant: 'standard' }, 'variant'>
) {
  return <UnifiedRepresentantForm {...props} variant="standard" />;
}

export function AvenantRepresentantForm(
  props: Omit<RepresentantFormProps & { variant: 'amendment' }, 'variant'>
) {
  return <UnifiedRepresentantForm {...props} variant="amendment" />;
}
