"use client"

import { useState, useEffect, useMemo } from "react"
import { Typography, Grid, Box, Alert, CircularProgress } from "@mui/material"
import FormField from "@/shared/components/form/form-field"
import type { FormFieldType, ModeType } from "@/shared/types/common"
import { usagerAvenantFormFields1, usagerAvenantFormFields2 } from "../../../utils/form-fields-avenant"
import TabbedForm from "@/shared/components/tabs/tabbed-form"
import HorairesSpecifiqueTabs from "./horaires-specifique-tabs"
import EditExportButtons from "@/shared/components/form/edit-export-buttons"
import RepresentantTabs from "../representant/representant-tabs"
import { FormikProvider, useFormik } from "formik"
import { avenantUsagerSchema } from "../../../utils/usager-validation"
import ConditionalComponent from "@/shared/components/table/ConditionalComponent"
import type { IPassengerList } from "@/shared/types/passenger"
import EtablissementJoursField from "@/shared/components/form/etablissement-jours-field"
import type { EstablishmentSchedule } from "@/shared/components/form/etablissement-jours-field"
import { etablissementsOptions } from "@/shared/_mock/_avenantUsager"
import type { AmendmentPassengerDetails } from "@/shared/types/ammendment-passenger"
import { useAmendmentPassengerStore } from "@/shared/api/stores/circuit-service/amendmentPassengerStore"
import { mapAmendmentToEstablishmentSchedules, mapEstablishmentSchedulesToAmendment } from "@/shared/sections/usager/utils/schedule-converters"
import { useEstablishmentStore } from "@/shared/api/stores/admin-service/establishmentStore"
import { convertFromFormikValues, convertToFormikValues, createEmptyFormikValues, extractExistingWeekIds } from "./utils/converters"
import { FormikAmendmentPassengerDetails } from "./types/formik-types"
import { enqueueSnackbar } from "notistack"
import ActionButtons from "@/shared/components/form/buttons-action"
import { getAmendmentParams } from "../../../hooks/use-amendment-passenger-table"
import { centerFlexColumn } from "@/shared/theme/css"
import AvenantRepresentant from "./components/avenant-representative"

interface AvenantUsagersFormProps {
  avenant: AmendmentPassengerDetails
  mode: ModeType
  onEdit: (updatedusager: AmendmentPassengerDetails, replaceCurrentTab?: boolean) => void
  onClose: (isSaved: boolean) => void;
  usager: IPassengerList,
  updateTabContent: (tabId: string, content: AmendmentPassengerDetails) => void,
  tabId: string,
  hasUnsavedChanges?: boolean,
  markTabAsSaved: (tabId: string, content: AmendmentPassengerDetails) => void,
}

const prependNomPrenom = (objetAvenant: string | undefined, nom: string, prenom: string) => {
  const nomPrenom = `${nom} ${prenom}: `
  return objetAvenant?.startsWith(nomPrenom) ? objetAvenant : nomPrenom + (objetAvenant || "")
}

export default function AvenantsHorairesFormEnhanced({
  avenant,
  mode,
  onClose,
  onEdit,
  usager,
  updateTabContent,
  tabId,
  hasUnsavedChanges,
  markTabAsSaved,
}: AvenantUsagersFormProps) {
  const isReadOnly = mode === "view"
  const { addAmendment, updateAmendment, loading, error, fetchAmendments } = useAmendmentPassengerStore()
  const [replaceCurrentTab, setReplaceCurrentTab] = useState(false);
  const [amendmentId, setAmendmentId] = useState<string>(avenant.id);
  const [establishmentSchedules, setEstablishmentSchedules] = useState<EstablishmentSchedule[]>([])
  const [establishmentOptions, setEstablishmentOptions] = useState<{ value: string; label: string }[]>([]);
  const { establishmentNamesAndIds, getAllEstablishmentNamesAndIds } = useEstablishmentStore();
  const [isSchedulesLoaded, setIsSchedulesLoaded] = useState(false);
  const [existingWeekIds, setExistingWeekIds] = useState<{ pair?: string | null; impair?: string | null }>({});

  useEffect(() => {
    const fetchData = async () => {
      await getAllEstablishmentNamesAndIds();
    };
    
    fetchData();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (establishmentNamesAndIds.length > 0) {
      setEstablishmentOptions(establishmentNamesAndIds.map((establishment) => ({
        value: establishment.id.toString(),
        label: establishment.name
      })));
    }
  }, [establishmentNamesAndIds]);
  
  const establishmentNames = useMemo(() => {
    return establishmentOptions.reduce(
      (acc, option) => {
        acc[Number.parseInt(option.value)] = option.label
        return acc
      },
      {} as Record<number, string>,
    )
  }, [establishmentOptions])


  const initialFormikValues = useMemo(() => {
    const weekIds = extractExistingWeekIds(avenant)
    setExistingWeekIds(weekIds)
    return convertToFormikValues(avenant)
  }, [avenant])

  
  useEffect(() => {
    setIsSchedulesLoaded(false)
    const mappedSchedules = mapAmendmentToEstablishmentSchedules(avenant, establishmentNames)
    setEstablishmentSchedules(mappedSchedules)
    setIsSchedulesLoaded(true)

  }, [avenant, establishmentNames])

  const formik = useFormik<FormikAmendmentPassengerDetails>({
    initialValues: initialFormikValues,
    validationSchema: avenantUsagerSchema,
    enableReinitialize:true,
    onSubmit: async (values) => {
      try {
        const backendAmendment = convertFromFormikValues(values, mode === "edit" ? existingWeekIds : undefined)

        const updatedAmendment = mapEstablishmentSchedulesToAmendment(establishmentSchedules, backendAmendment)

        const finalAmendment = {
          ...updatedAmendment,
          subject: prependNomPrenom(values.subject, usager.firstName, usager.lastName),
        }

        if (mode === "add") {
          const { id, ...amendmentWithoutId } = finalAmendment;
          const amendmentToSend = { ...amendmentWithoutId, passengerId: Number(usager.id) };
          const amendment = await addAmendment(amendmentToSend);
          enqueueSnackbar("Avenant ajouté avec succès" + amendment.id, { variant: 'success' });
          setAmendmentId(amendment.id)
          markTabAsSaved(tabId, amendment)
          formik.resetForm({ values: { ...values, id: amendment.id } as FormikAmendmentPassengerDetails });
          setReplaceCurrentTab(true);
        } else {
          await updateAmendment(avenant.id, finalAmendment)
          enqueueSnackbar("Avenant modifié avec succès", { variant: 'success' });
          await fetchAmendments(getAmendmentParams(Number(usager.id)))
          markTabAsSaved(tabId, updatedAmendment)
          formik.resetForm({ values })
        }
      } catch (error: any) {
        enqueueSnackbar(error.message, { variant: 'error' });
      }
    },
  })

  useEffect(() => {
    if (updateTabContent && tabId && !isReadOnly) {
      const timer = setTimeout(() => {
        updateTabContent(tabId, convertFromFormikValues(formik.values, existingWeekIds))
      }, 300)

      return () => {
        clearTimeout(timer)
      }
    }
  }, [formik.values, updateTabContent, tabId, isReadOnly, existingWeekIds])

  useEffect(() => {
    if (formik.dirty && !hasUnsavedChanges) {
      formik.resetForm();
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [hasUnsavedChanges])


  useEffect(() => {
    formik.setFieldValue("subject", prependNomPrenom(formik.values.subject, usager.firstName, usager.lastName))
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [usager.firstName, usager.lastName])

  const renderField = (field: FormFieldType<FormikAmendmentPassengerDetails>) => {
    const error = formik.touched[field.name] && formik.errors[field.name]
    return (
      <FormField
        field={field}
        value={formik.values[field.name]}
        onChange={(name, value) => formik.setFieldValue(name, value)}
        error={error ? String(formik.errors[field.name]) : undefined}
        isReadOnly={isReadOnly ?? (field.disabled && mode === "edit")}
        onBlur={formik.handleBlur}

      />
    )
  }
  const handleEdit = () => {
    onEdit({...avenant, id : amendmentId}, replaceCurrentTab);
  };
  const handleSave = () => {
    formik.validateForm().then((errors) => {
      formik.submitForm()
    })
  }

  const handleEstablishmentScheduleChange = (name: string, value: EstablishmentSchedule[]) => {
    setEstablishmentSchedules(value)
    formik.setFieldValue(
      "establishmentWeekPassengerMap",
      mapEstablishmentSchedulesToAmendment(value, convertFromFormikValues(formik.values)).establishmentWeekPassengerMap,
    )
  }
  const handleCancel = () => {
    onClose(false);
  };
  const getEstablishmentError = (index: number): string | undefined => {
    const errors = formik.errors?.establishmentWeekPassengerMap && formik.touched?.establishmentWeekPassengerMap
    if(errors) {  
      if ( typeof formik.errors.establishmentWeekPassengerMap === "string") {
          return formik.errors.establishmentWeekPassengerMap
      }

      if (Array.isArray(formik.errors.establishmentWeekPassengerMap)) {
        const error = formik.errors.establishmentWeekPassengerMap[index];
        if (error && typeof error !== 'string' && error.establishmentId) {
          return error.establishmentId;
        }
      }
  }
    return undefined
}
  const handleFieldBlur = (index: number) => {
    formik.handleBlur(`establishmentWeekPassengerMap[${index}].establishmentId`)    
  }
  const tabs = [
    {
      label: "Représentant, Adresses et Circuits",
      content: (
        <AvenantRepresentant passengerId={usager.id} scheduleMode={mode} onSave={handleSave} onClose={() => onClose(false)} mode={mode} onEdit={() => void 0} />
      ),
    },
    {
      label: "Horaires spécifiques",
      content: (
        <HorairesSpecifiqueTabs
          title="Horaires spécifiques de usager"
          mode={mode}
          withData={mode !== "add"}
          useFormik={true}
        />
      ),
    },
  ]

  if (loading || !isSchedulesLoaded) {
    return (
      <Box display="flex" justifyContent="center" alignItems="center" minHeight="200px">
        <CircularProgress />
      </Box>
    )
  }

  return (
    <Box
      sx={{
        pt: 3,
        px: 2,
        pb: 1,
        borderRadius: "0px 16px 16px 16px",
        border: (theme) => `2px solid ${theme.palette.primary.main}`,
      }}
    >
      <Typography
        variant="h5"
        sx={{
          color: "primary.main",
          fontWeight: (theme) => theme.typography.fontWeightBold,
          pb: 2,
        }}
      >
        Avenant usager
      </Typography>
      
      <ConditionalComponent isValid={isReadOnly}>
        <EditExportButtons onEdit={handleEdit} onExport={() => void 0} tooltipTitle="l'avenant" />
      </ConditionalComponent>

      <form onSubmit={formik.handleSubmit}>
        <Grid container spacing={4}>
          {usagerAvenantFormFields1(establishmentOptions).map((field) => (
            <ConditionalComponent
              key={field.name}
              defaultComponent={
                <EtablissementJoursField
                field={{
                  ...field,
                  name: 'etablissements',
                  label: 'Établissement'
                }}
                  values={{ establishmentTransportSchedules: establishmentSchedules }}
                  errors={getEstablishmentError}
                  isReadOnly={isReadOnly}
                  etablissementsOptions={etablissementsOptions}
                  onFieldChange={handleEstablishmentScheduleChange}
                  handleFieldBlur={handleFieldBlur}
                />
              }
              isValid={field.name !== "etablissement"}
            >
              <Grid item xs={12} sm={4} sx={centerFlexColumn} key={field.name}>
                {renderField(field as FormFieldType<FormikAmendmentPassengerDetails>)}
              </Grid>
            </ConditionalComponent>
          ))}
          {usagerAvenantFormFields2.map((field) => (
            <Grid item xs={12} sm={4} key={field.name}>
              {renderField(field)}
            </Grid>
          ))}
        </Grid>
        <FormikProvider value={formik}>
          <TabbedForm tabs={tabs} sx={{ mt: 4, mb: 1 }} hasBorder />
        </FormikProvider>

        <Grid item xs={12} sx={{ mt: 2 }}>
          <ActionButtons onSave={handleSave} onCancel={handleCancel} mode={mode} loading={loading} />
        </Grid>
      </form>
    </Box>
  )
}
