'use client';

import { Grid, Box, CircularProgress, Typography, FormHelperText } from '@mui/material';
import { useFormik, FormikProvider, getIn } from 'formik';
import FormField from '@/shared/components/form/form-field';
import type { FormFieldType, ModeType, TableColumn } from '@/shared/types/common';
import TabbedForm from '@/shared/components/tabs/tabbed-form';
import FormContainer from '@/layouts/form/form-container';
import { mainEtabformFields } from '../utils/form-fields-establishment';
import { EmptyPlaceholder } from '@/shared/components/column-selector/column-container';
import EtablissementVacanceForm from '../components/establishment-vacance';
import ConditionalComponent from '@/shared/components/table/ConditionalComponent';
import { useEffect, useState, useCallback, useRef } from 'react';
import { establishmentSchema } from '../utils/validation-schema-establishment';
import { Address, EstablishmentManager, EstablishmentRequest, EstablishmentTableItem, mapEstablishmentToEstablishmentRequest } from '@/shared/types/establishment';
import { useEstablishmentStore } from '@/shared/api/stores/admin-service/establishmentStore';
import { useInfrastructureStore } from '@/shared/api/stores/admin-service/infrastructureStore';
import EstablishmentDetailsForm from '../components/establishment-details';
import EstablishmentHoursForm from '../components/establishment-hours-form';
import { useZoneStore } from '@/shared/api/stores/admin-service/zoneStore';
import { useSnackbar } from 'notistack';
import { getFormatedAddress } from '@/shared/sections/exploitation/infrastructure/utils/address-utils';
import { useUserStore } from '@/shared/api/stores/user-service/user-store';

export interface RenderFieldOptions {
  onAddInfrastructure?: () => void;
}
interface EstablishmentFormProps {
  etablissement: EstablishmentTableItem;
  mode: ModeType;
  onSave: (updated: EstablishmentRequest) => void;
  onEdit: (updated: EstablishmentRequest) => void;
  onClose: (forceClose: boolean) => void;
  tableHead: TableColumn[];
  updateTabContent?: (tabId: string, newContent: EstablishmentRequest) => void
  tabId?: string
}


export default function EstablishmentForm({
  etablissement,
  mode,
  onSave,
  onClose,
  onEdit,
  tableHead,
  updateTabContent,
  tabId,
}: EstablishmentFormProps) {
  const { enqueueSnackbar } = useSnackbar();

  const {
    error,
    clearError,
    getEstablishmentById,
    establishmentById,
    createEstablishment,
    updateEstablishment,
    existsEstablishmentByCodeLoading,
    existsEstablishmentByCode,
    existsEstablishmentByUaiCodeLoading,
    existsEstablishmentByUaiCode
  } = useEstablishmentStore();

  const {
    error: infrastructureStoreError,
    clearError: clearInfrastructureStoreError,
    fetchDepartmentNames,
    departmentNames,
    getDepartmentHexColorById,
    departmentNameIdByDeparmentId,
    getDepartmentNameIdByDepartmentId
  } = useInfrastructureStore();

  const {
    fetchZoneNames,
    zoneNames
  } = useZoneStore();

  const [zoneOptions, setZoneOptions] = useState<{ label: string, value: string }[]>([]);
  const [departmentOptions, setDepartmentOptions] = useState<{ label: string, value: string }[]>([]);

  const [establishmentFormData, setEstablishmentFormData] = useState<EstablishmentRequest>({} as EstablishmentRequest);

  const [codeAvailability, setCodeAvailability] = useState<{ message: string, isAvailable: boolean } | null>(null);
  const [uaiCodeAvailability, setUaiCodeAvailability] = useState<{ message: string, isAvailable: boolean } | null>(null);
  const [managerPersonnalEmailAvailibility, setManagerPersonnalEmailAvailibility] = useState<{ message: string, isAvailable: boolean } | null>(null);


  const handleFormSubmit = async (values: EstablishmentRequest) => {
    const request = {
      ...values,
      address: getFormatedAddress(values.mapAddress)
    };
    if (!validateValues(request.address)) {
      enqueueSnackbar('Veuillez entrer une adresse valide !', { variant: 'error' });
      return;
    }
    if (formik.values.establishmentCode) {
      if (codeAvailability != null && !codeAvailability.isAvailable) {
        enqueueSnackbar('Veuillez entrer un code valide !', { variant: 'error' });
        return;
      }
    }
    if (formik.values.uaiCode) {
      if (uaiCodeAvailability != null && !uaiCodeAvailability.isAvailable) {
        enqueueSnackbar('Veuillez entrer un uai code valide !', { variant: 'error' });
        return;
      }
    }
    if (!validateManager(request.establishmentManager)) {
      enqueueSnackbar('Veuillez renseigner un responsable valide (nom, prénom et email).', { variant: 'error' });
      return;
    }
    if (mode === 'edit') {
      try {
        await updateEstablishment(etablissement.id, request);
        onClose(true);
        enqueueSnackbar('Etablissement modifié avec succès', { variant: 'success' });
      } catch (error: any) {
        enqueueSnackbar(error.message, { variant: 'error' });
        clearError();
        return;
      }
    } else if (mode === 'add' || mode === 'copy') {
      try {
        await createEstablishment(request);
        onClose(true);
        enqueueSnackbar('Etablissement créé avec succès', { variant: 'success' });
      } catch (error: any) {
        enqueueSnackbar(error.message, { variant: 'error' });
        clearError();
        return;
      }
    }
    formik.resetForm();
  };

  function validateValues(address: Address): boolean {
    if (
      address &&
      !address.street ||
      address.latitude === undefined ||
      address.longitude === undefined ||
      isNaN(address.latitude) ||
      isNaN(address.longitude)
    ) {
      return false;
    }
    return true;
  }

  function validateManager(manager?: Partial<EstablishmentManager> | null): boolean {
    if (!manager) return true;

    const {
      firstName = '',
      lastName = '',
      personalEmail = '',
      phoneNumber = '',
      civility = undefined as any
    } = manager;

    const anyFieldFilled =
      [firstName, lastName, personalEmail, phoneNumber]
        .some(v => typeof v === 'string' ? v.trim() !== '' : false)
      || civility != null;

    if (!anyFieldFilled) return true;

    if (!firstName.trim() || !lastName.trim() || !personalEmail.trim()) return false;

    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(personalEmail)) return false;

    return true;
  }

  const formik = useFormik<EstablishmentRequest>({
    initialValues: establishmentFormData,
    validationSchema: establishmentSchema,
    enableReinitialize: true,
    onSubmit: handleFormSubmit,
  });

  const getInitialValues = async () => {
    await fetchDepartmentNames();
    await fetchZoneNames();
    if (etablissement.id && mode !== 'add') {
      await getEstablishmentById(etablissement.id);
    }
  }

  useEffect(() => {
    getInitialValues();
  }, []);

  useEffect(() => {
    if (departmentNames) {
      setDepartmentOptions(departmentNames.map((department) => ({ label: department.name, value: department.id.toString() })));
    }
    if (establishmentById && mode !== 'add') {
      setEstablishmentFormData(mapEstablishmentToEstablishmentRequest(establishmentById));
    }
    if (zoneNames) {
      setZoneOptions(zoneNames.map((zone) => ({ label: zone.name, value: zone.id.toString() })));
    }
  }, [departmentNames, establishmentById, zoneNames, mode]);

  useEffect(() => {
    if (mode === 'add') {
      setEstablishmentFormData({} as EstablishmentRequest)
      formik.setFieldValue('colorCode', '');
    }
  }, [mode])

  useEffect(() => {
    const fetchColorForDepartment = async () => {
      if (formik.values.departmentId) {
        const color = await getDepartmentHexColorById(formik.values.departmentId?.toString());
        if (color) formik.setFieldValue('colorCode', color);
      }
    };

    if (formik.values.departmentId) {
      fetchColorForDepartment();
      getDepartmentNameIdByDepartmentId(formik.values.departmentId);
    }
  }, [formik.values.departmentId]);

  useEffect(() => {
    if (departmentNameIdByDeparmentId) {
      formik.setFieldValue('zoneId', departmentNameIdByDeparmentId.zoneId);
    } else {
      formik.setFieldValue('zoneId', '');
    }
  }, [departmentNameIdByDeparmentId])

  useEffect(() => {
    if (updateTabContent && tabId && (mode !== "view")) {
      updateTabContent(tabId, formik.values)
    }
  }, [formik.values, updateTabContent, tabId, mode])

  const isReadOnly = mode === 'view';
  const isAddMode = mode === 'add';

  const codeTimeoutRef = useRef<NodeJS.Timeout>();
  const uaiCodeTimeoutRef = useRef<NodeJS.Timeout>();

  const checkCode = useCallback((code: string) => {
    if (codeTimeoutRef.current) {
      clearTimeout(codeTimeoutRef.current);
    }

    if (!code) {
      setCodeAvailability(null);
      return;
    }

    const trimmedCode = code.trim();
    if (trimmedCode === '') {
      setCodeAvailability(null);
      return;
    }

    codeTimeoutRef.current = setTimeout(() => {
      const verifyCode = async () => {
        try {
          const exists = mode === 'edit'
            ? await existsEstablishmentByCode(trimmedCode, Number(etablissement.id))
            : await existsEstablishmentByCode(trimmedCode);

          setCodeAvailability({
            message: exists ? 'Le code existe déjà' : 'Le code est disponible',
            isAvailable: !exists
          });
        } catch (error) {
          setCodeAvailability(null);
        }
      };

      verifyCode();
    }, 500);
  }, [mode, etablissement.id, existsEstablishmentByCode]);

  const checkUaiCode = useCallback((uaiCode: string) => {
    if (uaiCodeTimeoutRef.current) {
      clearTimeout(uaiCodeTimeoutRef.current);
    }

    if (!uaiCode) {
      setUaiCodeAvailability(null);
      return;
    }

    const trimmedUaiCode = uaiCode.trim();
    if (trimmedUaiCode === '') {
      setUaiCodeAvailability(null);
      return;
    }

    uaiCodeTimeoutRef.current = setTimeout(() => {
      const verifyUaiCode = async () => {
        try {
          const exists = mode === 'edit'
            ? await existsEstablishmentByUaiCode(trimmedUaiCode, Number(etablissement.id))
            : await existsEstablishmentByUaiCode(trimmedUaiCode);

          setUaiCodeAvailability({
            message: exists ? 'Le code UAI existe déjà' : 'Le code UAI est disponible',
            isAvailable: !exists
          });
        } catch (error) {
          setUaiCodeAvailability(null);
        }
      };

      verifyUaiCode();
    }, 500);
  }, [mode, etablissement.id, existsEstablishmentByUaiCode]);

  useEffect(() => {
    return () => {
      if (codeTimeoutRef.current) {
        clearTimeout(codeTimeoutRef.current);
      }
      if (uaiCodeTimeoutRef.current) {
        clearTimeout(uaiCodeTimeoutRef.current);
      }
    };
  }, []);

  const renderField = (field: FormFieldType<EstablishmentRequest>, options?: RenderFieldOptions) => {
    const isPersonalEmailAlias = field.name === 'responsibleEmail';
    const path = isPersonalEmailAlias ? 'establishmentManager.personalEmail' : field.name;

    const showErr =
      (getIn(formik.touched, field.name) || formik.submitCount > 0) &&
      getIn(formik.errors, field.name);
    const isColorCodeAutoFilled = field.name === 'colorCode';

    const finalFieldName = isPersonalEmailAlias ? 'establishmentManager.personalEmail' : field.name;

    return (
      <>
        <FormField
          onAddInfrastructure={options?.onAddInfrastructure}
          field={field}
          value={
            field.name === 'zoneId' ? String(formik.values[field.name as keyof EstablishmentRequest]) :
              field.name === 'departmentId' ? String(formik.values[field.name as keyof EstablishmentRequest]) :
                formik.values[field.name]
          }
          onChange={(name, value) => {
            formik.setFieldValue(name, value);
            if (finalFieldName === 'establishmentCode') {
              checkCode(value);
            }
            if (finalFieldName === 'uaiCode') {
              checkUaiCode(value);
            }
          }}
          error={finalFieldName === 'mapAddress'
            ? (getIn(formik.touched, 'mapAddress.address') || formik.submitCount > 0) && getIn(formik.errors, 'mapAddress.address')
            : showErr}
          isReadOnly={isReadOnly || isColorCodeAutoFilled || field.name === 'zoneId'}
          onBlur={formik.handleBlur}
        />
        <ConditionalComponent isValid={path === 'establishmentCode'}>
          <FormHelperText
            sx={{
              color: existsEstablishmentByCodeLoading ? 'text.secondary' : (codeAvailability?.isAvailable ? 'success.main' : 'error.main'),
              marginTop: '4px',
              display: 'flex',
              alignItems: 'center'
            }}
          >
            <ConditionalComponent isValid={existsEstablishmentByCodeLoading}>
              <Box sx={{ display: 'flex', alignItems: 'center' }}>
                <Box
                  sx={{
                    width: '16px',
                    height: '16px',
                    border: '2px solid #f3f3f3',
                    borderTop: '2px solid #746CD4',
                    borderRadius: '50%',
                    animation: 'spin 1s linear infinite',
                    marginRight: '8px',
                    '@keyframes spin': {
                      '0%': { transform: 'rotate(0deg)' },
                      '100%': { transform: 'rotate(360deg)' }
                    }
                  }}
                />
                <Typography sx={{ color: '#746CD4' }}>
                  Vérification en cours...
                </Typography>
              </Box>
            </ConditionalComponent>
            <ConditionalComponent isValid={!existsEstablishmentByCodeLoading}>
              {codeAvailability?.message}
            </ConditionalComponent>
          </FormHelperText>
        </ConditionalComponent>
        <ConditionalComponent isValid={path === 'uaiCode'}>
          <FormHelperText
            sx={{
              color: existsEstablishmentByUaiCodeLoading ? 'text.secondary' : (uaiCodeAvailability?.isAvailable ? 'success.main' : 'error.main'),
              marginTop: '4px',
              display: 'flex',
              alignItems: 'center'
            }}
          >
            <ConditionalComponent isValid={existsEstablishmentByUaiCodeLoading}>
              <Box sx={{ display: 'flex', alignItems: 'center' }}>
                <Box
                  sx={{
                    width: '16px',
                    height: '16px',
                    border: '2px solid #f3f3f3',
                    borderTop: '2px solid #746CD4',
                    borderRadius: '50%',
                    animation: 'spin 1s linear infinite',
                    marginRight: '8px',
                    '@keyframes spin': {
                      '0%': { transform: 'rotate(0deg)' },
                      '100%': { transform: 'rotate(360deg)' }
                    }
                  }}
                />
                <Typography sx={{ color: '#746CD4' }}>
                  Vérification en cours...
                </Typography>
              </Box>
            </ConditionalComponent>
            <ConditionalComponent isValid={!existsEstablishmentByUaiCodeLoading}>
              {uaiCodeAvailability?.message}
            </ConditionalComponent>
          </FormHelperText>
        </ConditionalComponent>
      </>
    );
  };

  const tabs = [
    {
      label: 'Coordonnée',
      content: (
        <EstablishmentDetailsForm
          renderField={renderField}
          mode={mode}
          onEdit={() => onEdit(formik.values)}
          onClose={() => onClose(false)}
          etablissement={formik.values}
          tableHead={tableHead}
          zoneOptions={zoneOptions}
          departmentOptions={departmentOptions}
        />
      ),
    },
    {
      label: 'Horaires',
      content: (
        <EstablishmentHoursForm
          onEdit={() => onEdit(formik.values)}
          onClose={() => onClose(false)}
          mode={mode}
          formik={formik}
        />
      ),
    },
    {
      label: 'Vacance',
      content: (
        <ConditionalComponent
          isValid={isAddMode || mode === 'copy'}
          defaultComponent={<EtablissementVacanceForm />}
        >
          <EmptyPlaceholder text="Les vacances peuvent être saisies une fois que vous avez enregistré la fiche." />
        </ConditionalComponent>
      )
    },
  ];

  useEffect(() => {
    if (error) {
      enqueueSnackbar(error, { variant: 'error' });
      clearError();
    }
  }, [error, enqueueSnackbar, clearError]);

  useEffect(() => {
    if (infrastructureStoreError) {
      enqueueSnackbar(infrastructureStoreError, { variant: 'error' });
      clearInfrastructureStoreError();
    }
  }, [infrastructureStoreError, enqueueSnackbar, clearInfrastructureStoreError]);

  return (
    <FormikProvider value={formik}>
      <FormContainer titre="Fiche d'un établissement">
        <form onSubmit={formik.handleSubmit}>
          <Grid container spacing={5}>
            {mainEtabformFields().map((etablissement) => (
              <Grid
                item
                xs={12}
                sm={etablissement.name === 'uaiCode' ? 4 : 8}
                key={etablissement.name}
              >
                {renderField(etablissement)}
              </Grid>
            ))}
          </Grid>
          <TabbedForm tabs={tabs} sx={{ mt: 4 }} />
        </form>
      </FormContainer>
    </FormikProvider>
  );
}