"use client"

import { Typography, Grid, Dialog, DialogTitle, DialogContent, Box, debounce } from "@mui/material"
import { getAddPointFormFields } from "../utils/form-fields-trajet"
import type { AddressData, FormFieldType } from "@/shared/types/common"
import FormField from "@/shared/components/form/form-field"
import { useState, useMemo, useEffect, useCallback } from "react"
import type { IAddPoint, IAddPointRequest } from "@/shared/types/trajet"
import { INITIAL_ADD_POINT_DATA } from "@/shared/_mock/_trajets"
import dynamic from "next/dynamic"
import { type RouteMarker, MapType, type CircuitMap, type LatLng } from "@/shared/types/Maps"
import { useFormik } from "formik"
import { addPointValidationSchema } from "../utils/add-point-validation-schema"
import { usePassengersCircuitStore } from "@/shared/api/stores/circuit-service/passengerscircuitStore"
import { enqueueSnackbar } from "notistack"
import type { WeekTypeSchedule } from "@/shared/types/circuit"
import { getTripMarkerIcon } from "@/shared/components/google-maps/utils/marker-icon"
import { mapAddressToMapAddresse } from "@/shared/types/establishment"
import { convertAddressDataToAddress } from "../utils/address-converter"
import { useEstablishmentSearch } from "@/shared/sections/usager/hooks/use-establishment-search"
import { useEstablishmentStore } from "@/shared/api/stores/admin-service/establishmentStore"
import { useTripPointStore } from "@/shared/api/stores/circuit-service/tripPointStore"
import ActionButtons from "@/shared/components/form/buttons-action"
import { loadingPassengerDetailsStyles } from "@/shared/theme/css"
import { StyledCircularProgress } from "@/shared/components/form/style"

const MapView = dynamic(() => import("@/shared/components/google-maps/mapsPoints"), {
  ssr: false,
})

interface Props {
  open: boolean
  onClose: () => void
  tripId: string
  reactiveMapRoutes: CircuitMap[]
  mapMarkers: RouteMarker[]
  weeklySchedules: WeekTypeSchedule[]
  displayNewTrip: (newTripId: string) => void
}

export default function AddPointModal({ open, onClose, tripId, reactiveMapRoutes, mapMarkers, weeklySchedules, displayNewTrip }: Props) {
  const [localMapMarkers, setLocalMapMarkers] = useState<RouteMarker[]>(mapMarkers)
  const [establishmentOptions, setEstablishmentOptions] = useState<{ value: string; label: string }[]>([]);

  const {
    passengersWithNoCircuit,
    loadingPassengers,
    error: passengersError,
    searchPassengersWithNoCircuit,
    getPassengerDetails,
    loadingPassengerDetails,
  } = usePassengersCircuitStore()

  const { searchEstablishments } = useEstablishmentSearch()
  const { establishmentNamesAndIds } = useEstablishmentStore()
  const { addPoint, addPointLoading } = useTripPointStore()

  const passengersOptions = useMemo(() => {
    return passengersWithNoCircuit.map((passenger) => ({
      label: `${passenger.firstName} ${passenger.lastName}`,
      value: passenger.id.toString(),
    }))
  }, [passengersWithNoCircuit])

  useEffect(() => {
    if (establishmentNamesAndIds.length > 0) {
      setEstablishmentOptions(establishmentNamesAndIds.map((establishment) => ({
        value: establishment.id.toString(),
        label: establishment.name
      })));
    }
  }, [establishmentNamesAndIds]);

  const debouncedSearch = useMemo(() => {
    const searchFunction = async (searchTerm?: string) => {
      if (!searchTerm) return
      try {
        await searchPassengersWithNoCircuit(searchTerm.trim())
      } catch (error: any) {
        enqueueSnackbar(error.message || "Erreur lors du chargement des passagers", {
          variant: "error",
        })
      }
    }

    return debounce(searchFunction, 300)
  }, [searchPassengersWithNoCircuit])

  useEffect(() => {
    if (open) {
      setLocalMapMarkers(mapMarkers)
      searchPassengersWithNoCircuit('')
    }
  }, [open, searchPassengersWithNoCircuit, mapMarkers])

  const formik = useFormik<IAddPoint>({
    initialValues: INITIAL_ADD_POINT_DATA,
    validationSchema: addPointValidationSchema,
    onSubmit: () => { },
  })

  const getMarkerIcon = useCallback(
    (index: number, total: number, isPointAnEstablishment: boolean) =>
      getTripMarkerIcon(index, total, isPointAnEstablishment, false),
    []
  );

  const updateMarkersAndRoute = (position: LatLng, title: string) => {
    const newMarkers = [...localMapMarkers]
    const tempMarkerId = 'temp-new-point'
    const existingTempIndex = newMarkers.findIndex(marker => marker.id === tempMarkerId)

    if (existingTempIndex !== -1) {
      newMarkers[existingTempIndex] = {
        ...newMarkers[existingTempIndex],
        position,
        title,
        icon: getMarkerIcon(newMarkers.length - 1, newMarkers.length, false) as string,
      }
    } else {
      const newMarker: RouteMarker = {
        id: tempMarkerId,
        position,
        title,
        icon: getMarkerIcon(newMarkers.length, newMarkers.length + 1, false) as string,
      }
      newMarkers.push(newMarker)
    }

    setLocalMapMarkers(newMarkers)
  }

  const handleAddressChange = (address: AddressData) => {
    if (!address) return

    if (address.lat && address.lng) {
      const newPosition = {
        lat: address.lat,
        lng: address.lng,
      }

      updateMarkersAndRoute(newPosition, address.address)
    }
  }

  const handleUserSelection = async (userId: string) => {
    if (!userId) return

    try {
      const passengerDetails = await getPassengerDetails({
        passengerId: Number(userId),
        weeklySchedules: weeklySchedules
      })
      
      formik.setFieldValue("establishment", passengerDetails.establishmentName)
      formik.setFieldValue("establishmentId", passengerDetails.establishmentId)

      const addressData: AddressData = mapAddressToMapAddresse(passengerDetails.address) 
      formik.setFieldValue("endPointAddress", addressData)

      const newPosition = {
        lat: addressData.lat,
        lng: addressData.lng,
      }

      const additionalAddress = passengerDetails.address.additionalAddress
      
      const passengerLabel = passengersOptions.find(option => option.value === userId)?.label
      
      const label = additionalAddress && additionalAddress.trim() !== ''
        ? additionalAddress
        : addressData.address

      updateMarkersAndRoute(newPosition, passengerLabel || label)
    } catch (error: any) {
      enqueueSnackbar(error.message || "Erreur lors de la récupération des données de l'utilisateur", {
        variant: "error",
      })
    }
  }

  const handleClose = () => {
    formik.resetForm()
    const filteredMarkers = localMapMarkers.filter(marker => marker.id !== 'temp-new-point')
    setLocalMapMarkers(filteredMarkers)
    onClose()
  }

  const handleValidateClick = async () => {
    try {
      const values = formik.values
      
      const addressForBackend = convertAddressDataToAddress(values.endPointAddress)
      
      const addPointRequest: IAddPointRequest = {
        tripId: tripId,
        titleEndPoint: values.titleEndPoint,
        endPointAddress: addressForBackend,
        passengerId: values.passengerId,
        establishment: values.establishment,
        establishmentId: values.establishmentId,
      }
      const newTripId = await addPoint(addPointRequest)
      enqueueSnackbar("Point ajouté avec succès", {
        variant: "success",
      })
      displayNewTrip(newTripId)
      handleClose()
    } catch (error: any) {
      enqueueSnackbar(error.message, {
        variant: "error",
      })
    }
  }

  const renderField = (field: FormFieldType<IAddPoint>) => {
    const isUserField = field.name === "passengerId"
    const isAddressField = field.name === "titleEndPoint"
    const isEstablishmentField = field.name === "establishmentId"
    const hasUserValue = formik.values.passengerId && formik.values.passengerId !== ""
    const hasAddressValue = formik.values.titleEndPoint && formik.values.titleEndPoint !== ""

    const shouldBeReadOnly = Boolean(field.disabled ||
      (isUserField && hasAddressValue) ||
      (isAddressField && hasUserValue) || (isEstablishmentField && !hasUserValue))

    if (field.name === "endPointAddress") {
      return (
        <FormField
          field={field}
          value={formik.values.endPointAddress.address}
          onChange={(name, value) => {
            formik.setFieldValue(name, value)
            handleAddressChange(value)
          }}
          error={formik.touched.endPointAddress ? (formik.errors.endPointAddress as string) : undefined}
          onBlur={formik.handleBlur}
          isReadOnly={false}
        />
      )
    }

    return (
      <FormField
        field={field}
        value={formik.values[field.name as keyof IAddPoint]}
        onChange={(name, value) => {
          formik.setFieldValue(name, value)
          if (isUserField && value && value !== "") {
            handleUserSelection(value)
          }
          if (isAddressField && value && value !== "") {
            formik.setFieldValue("establishment", "")
            formik.setFieldValue("establishmentId", undefined)
          }
          if (isEstablishmentField && value && value !== "") {
            formik.setFieldValue("establishment", establishmentOptions.find(option => option.value === value)?.label)
          }
        }}
        error={
          formik.touched[field.name as keyof IAddPoint]
            ? (formik.errors[field.name as keyof IAddPoint] as string)
            : undefined
        }
        onBlur={formik.handleBlur}
        isReadOnly={shouldBeReadOnly}
      />
    )
  }

  return (
    <Dialog open={open} onClose={handleClose} fullWidth maxWidth="xl">
      <DialogTitle>
        <Typography variant="h5" color="primary.main">
          Ajout d&apos;un point
        </Typography>
      </DialogTitle>
      <DialogContent>
        <form>
          <Grid container spacing={2}>
            {getAddPointFormFields(establishmentOptions, searchEstablishments, passengersOptions, debouncedSearch).map((field: FormFieldType<IAddPoint>, index: number) => (
              <Grid item key={index} xs={12}>
                  <Box sx={{ position: "relative" }}>
                    {renderField(field)}
                    {field.name === "passengerId" && loadingPassengerDetails && (
                      <Box sx={loadingPassengerDetailsStyles}>
                        <StyledCircularProgress size={20} />
                      </Box>
                    )}
                  </Box>              </Grid>
            ))}
            <Grid item xs={12}>
              <Box sx={{ width: "100%", height: "360px", border: "1px solid #e0e0e0", borderRadius: 1 }}>
                <MapView
                  height="360px"
                  width="100%"
                  Submodule={MapType.CIRCUIT}
                  routes={reactiveMapRoutes}
                  markers={localMapMarkers}
                  defaultCenter={{ lat: 43.296482, lng: 5.36978 }}
                  defaultZoom={13}
                />
              </Box>
            </Grid>

            <Grid item xs={12} sx={{ mt: 2 }}>
          <ActionButtons onSave={handleValidateClick} onCancel={handleClose} loading={addPointLoading} />
        </Grid>
          </Grid>
        </form>
      </DialogContent>
    </Dialog>
  )
}
