'use client';

import { useEffect, useState, useCallback, useMemo } from 'react';
import dynamic from 'next/dynamic';
import dayjs from 'dayjs';
import { DndContext, type DragEndEvent } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy, arrayMove } from '@dnd-kit/sortable';
import {
  CircularProgress,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableRow,
  Typography,
} from '@mui/material';
import { Box, Stack } from '@mui/system';
import { enqueueSnackbar } from 'notistack';
import SvgColor from '@/shared/components/svg-color';
import { AddButton, ColumnButton, outlinedColor } from '@/shared/components/table/styles';
import { errorAlertStyles, StyledTableContainer } from '@/shared/theme/css';
import { JourneySummary } from '@/shared/components/google-maps/journey-summary';
import { MapType, type RouteMarker, type CircuitMap } from '@/shared/types/Maps';
import { HeaderCell } from '@/shared/components/form/style';
import AddPointModal from '@/shared/sections/trajet/components/add-point-modal';
import { StatusColor } from '@/shared/sections/chauffeur/planingChauffeur/utils/schedule-utils';
import ConditionalComponent from '@/shared/components/table/ConditionalComponent';
import type { TripCircuitDetails, TripPointDetails } from '@/shared/types/circuit';
import FontAwesome from '@/shared/components/fontawesome';
import { faCircleExclamation, faSquarePlus } from '@fortawesome/free-solid-svg-icons';
import { DEFAULT_SUIVIT_TRAJET_TABLE_HEAD } from '@/shared/_mock/_trajets';
import { useTripPointStore } from '@/shared/api/stores/circuit-service/tripPointStore';
import { useTripCircuitStore } from '@/shared/api/stores/circuit-service/tripCircuitStore';
import { useCircuitStore } from '@/shared/api/stores/circuit-service/circuitStore';
import { SensTrip } from '@/shared/types/passenger';
import { getTripMarkerIcon } from '@/shared/components/google-maps/utils/marker-icon';
import { decodePolyline } from '@/shared/sections/trajet/utils/maps-utils';
import { BaseStyledRow } from '@/shared/sections/contract/styles';
import { SortablePlanningTrajetRow } from './sortable-planning-trajet-row';

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

interface TrajetFormProps {
  mode: string;
  isDrawerElement?: boolean;
  trajetId: string;
  trajet: TripCircuitDetails;
  isGoogleLoaded?: boolean;
  handleView: (item: TripCircuitDetails) => void;
  onClose: () => void;
  selectedType: 'personnalisé' | 'dupliqué' | 'view';
  editable?: boolean;
}

declare global {
  interface Window {
    google: any;
  }
}

export default function DetailsPlanningTrajet({
  mode = 'edit',
  isDrawerElement = false,
  trajetId,
  trajet,
  isGoogleLoaded,
  handleView,
  onClose,
  selectedType,
  editable
}: TrajetFormProps) {
  const [reactiveMapRoutes, setReactiveMapRoutes] = useState<CircuitMap[]>([]);
  const { swapSequenceOrder, updateArrivalTime, loading } = useTripPointStore();
  const { getTripCircuitById } = useTripCircuitStore();
  const { recalculateTrip, recalculateLoading } = useCircuitStore();
  const [sortedData, setSortedData] = useState<TripPointDetails[]>(trajet.tripPoints);
  const [mapMarkers, setMapMarkers] = useState<RouteMarker[]>([]);
  const [modalOpen, setModalOpen] = useState(false);
  const [editingHoraireId, setEditingHoraireId] = useState<string | null>(null);
  const [routePath, setRoutePath] = useState<google.maps.LatLngLiteral[]>([]);
  const [hasChanges, setHasChanges] = useState(false);
  const handleRecalculateTrip = async () => {
    try {
      const id = await recalculateTrip(trajetId);
      displayNewTrip(id);
      setHasChanges(false);
      enqueueSnackbar('Le trajet a été recalculé avec succès', { variant: 'success' });
    } catch (error: any) {
      enqueueSnackbar(error.message || 'Erreur lors du recalcul du trajet', { variant: 'error' });
    }
  };
  const displayNewTrip = async (newTripId: string) => {
    const details = await getTripCircuitById(newTripId);
    if (details) {
      onClose();
      handleView(details);
    }
  }

  useEffect(() => {
    if (trajet?.shortestPath?.routes?.length > 0 && isGoogleLoaded) {
      const mainRoute = trajet.shortestPath.routes[0];
      const checkAndDecode = () => {
        if (
          typeof window !== 'undefined' &&
          window.google &&
          window.google.maps &&
          window.google.maps.geometry &&
          window.google.maps.geometry.encoding
        ) {
          const decodedPath = decodePolyline(mainRoute.geometry);
          setRoutePath(decodedPath);
        } else {
          setTimeout(checkAndDecode, 100);
        }
      };

      checkAndDecode();
    } else {
      setRoutePath([]);
    }
  }, [trajet, isGoogleLoaded]);

  const getMarkerIcon = useCallback(
    (index: number, total: number, isPointAnEstablishment: boolean) =>
      getTripMarkerIcon(index, total, isPointAnEstablishment, trajet.sens === SensTrip.DEPARTURE),
    [trajet.sens]
  );

  useEffect(() => {
    if (!sortedData || sortedData.length === 0 || !isGoogleLoaded) {
      setMapMarkers([]);
      return;
    }
    const newMarkers = sortedData
      .map((point, index) => {
        const coords = point.passengerDetailsTrip?.startCoordinates;
        const isPointAnEstablishment: boolean = point.passengerDetailsTrip.fullName === null;
        if (!coords) return null;
        const lat = coords.latitude;
        const lng = coords.longitude;
        if (isNaN(lat) || isNaN(lng)) return null;
        return {
          id: point.id || `point-${index + 1}`,
          position: { lat, lng },
          title:
            point.passengerDetailsTrip?.fullName ||
            point.passengerDetailsTrip?.establishmentName ||
            `Point ${index + 1}`,
          icon: getMarkerIcon(index, sortedData.length, isPointAnEstablishment),
          color: StatusColor.PRIMARY,
        } as RouteMarker;
      })
      .filter((marker): marker is RouteMarker => marker !== null);
    setMapMarkers(newMarkers);
  }, [sortedData, getMarkerIcon, isGoogleLoaded]);
  
  const handleCommitHoraireChange = useCallback(
    async (rowId: string, newValue: dayjs.Dayjs | null) => {
      if (!newValue || !newValue.isValid()) {
        setEditingHoraireId(null);
        return;
      }

      const newHoraire = newValue.format('HH:mm:ss');
      try {
        await updateArrivalTime(rowId, newHoraire);

        setSortedData((prev) =>
          prev.map((row) =>
            row.id === rowId
              ? {
                ...row,
                passengerDetailsTrip: { ...row.passengerDetailsTrip, pickupTime: newHoraire },
              }
              : row
          )
        );

        setHasChanges(true);

        enqueueSnackbar("L'horaire a été mis à jour avec succès", { variant: 'success' });
      } catch (error: any) {
        enqueueSnackbar(error.message || "Erreur lors de la mise à jour de l'horaire", {
          variant: 'error',
        });
      } finally {
        setEditingHoraireId(null);
      }
    },
    [updateArrivalTime]
  );
  const handleDragEnd = useCallback(
    async (event: DragEndEvent) => {
      if (selectedType === 'view') {
        enqueueSnackbar(
          "Impossible de changer l'ordre en mode 'view'. Passez en personnalisation ou duplication pour modifier l'ordre.",
          { variant: 'warning' }
        );
        return;
      }
      else if (!editable) {
        enqueueSnackbar(
          "Impossible de changer l'ordre avant de remplir le champ Observation/ Objet de personnalisation , veuillez le remplir s'il vous plait",
          { variant: 'warning' }
        );
        return;
      }
      const { active, over } = event;
      if (over && active.id !== over.id) {
        const oldIndex = sortedData.findIndex((item) => item.id === active.id);
        const newIndex = sortedData.findIndex((item) => item.id === over.id);
        const activeItem = sortedData[oldIndex];
        const overItem = sortedData[newIndex];

        if (
          (activeItem.passengerDetailsTrip.establishmentName &&
            !overItem.passengerDetailsTrip.establishmentName) ||
          (!activeItem.passengerDetailsTrip.establishmentName &&
            overItem.passengerDetailsTrip.establishmentName)
        ) {
          enqueueSnackbar(
            "Les établissements ne peuvent être échangés qu'avec d'autres établissements",
            {
              variant: 'warning',
            }
          );
          return;
        }

        try {
          const [firstItemId, secondItemId] =
            oldIndex < newIndex ? [activeItem.id, overItem.id] : [overItem.id, activeItem.id];

          await swapSequenceOrder(trajetId, firstItemId, secondItemId);

          const newSortedData = arrayMove(sortedData, oldIndex, newIndex);
          setSortedData(newSortedData);
          setHasChanges(true);
          enqueueSnackbar("L'ordre des points a été mis à jour avec succès", {
            variant: 'success',
          });
        } catch (error: any) {
          enqueueSnackbar(error.message || "Erreur lors de la mise à jour de l'ordre des points", {
            variant: 'error',
          });
        }
      }
    },
    [sortedData, swapSequenceOrder, trajetId, selectedType, editable]
  );

  const renderRow = useCallback(
    (row: TripPointDetails) => {
      return (
        <SortablePlanningTrajetRow
          key={row.id}
          row={row}
          tableHead={tableHead}
          editingHoraireId={editingHoraireId}
          setEditingHoraireId={setEditingHoraireId}
          handleCommitHoraireChange={handleCommitHoraireChange}
          selectedType={selectedType}
          editable={editable}
        />
      );
    },
    [editingHoraireId, setEditingHoraireId, handleCommitHoraireChange, selectedType,editable]
  );

  const mapRoutes: CircuitMap[] =
    routePath.length > 0
      ? [
        {
          id: trajet.id || 'current',
          name: 'Current Route',
          color: StatusColor.PRIMARY,
          path: routePath,
          startPoint: mapMarkers[0]
            ? {
              position: mapMarkers[0].position,
              title: mapMarkers[0].title,
            }
            : undefined,
          endPoint:
            mapMarkers.length > 0
              ? {
                position: mapMarkers[mapMarkers.length - 1].position,
                title: mapMarkers[mapMarkers.length - 1].title,
              }
              : undefined,
          users: mapMarkers.slice(1, -1).map((marker) => ({
            id: marker.id,
            position: marker.position,
            title: marker.title,
          })),
        },
      ]
      : [];

  useEffect(() => {
    const mapRoutes: CircuitMap[] =
      routePath.length > 0
        ? [
          {
            id: trajet.id || 'current',
            name: 'Current Route',
            color: StatusColor.PRIMARY,
            path: routePath,
            startPoint: mapMarkers[0]
              ? {
                position: mapMarkers[0].position,
                title: mapMarkers[0].title,
              }
              : undefined,
            endPoint:
              mapMarkers.length > 0
                ? {
                  position: mapMarkers[mapMarkers.length - 1].position,
                  title: mapMarkers[mapMarkers.length - 1].title,
                }
                : undefined,
            users: mapMarkers.slice(1, -1).map((marker) => ({
              id: marker.id,
              position: marker.position,
              title: marker.title,
            })),
          },
        ]
        : [];
    setReactiveMapRoutes(mapRoutes);
  }, [mapMarkers, routePath, trajet.id]);
  return (
    <Box sx={{ width: '100%' }}>
      <Stack flexGrow={0} direction="row" alignItems="center" justifyContent="right" gap={1} py={2}>
        <ConditionalComponent isValid={!(mode === 'view' && isDrawerElement)}>
          <ColumnButton
            sx={{ ...outlinedColor }}
            variant="outlined"
            disabled={!hasChanges || recalculateLoading}
            onClick={handleRecalculateTrip}
            endIcon={
              recalculateLoading ? (
                <CircularProgress size={16} sx={{ color: 'grey.500' }} />
              ) : (
                <SvgColor
                  src="/assets/icons/menu/ic_exploitation.svg"
                  sx={{ width: 16, height: 16 }}
                />
              )
            }
          >
            {'Calcul trajet / horaire'}
          </ColumnButton>
        </ConditionalComponent>
        <ConditionalComponent isValid={!(mode === 'view' && isDrawerElement)}>
          <AddButton
            variant="contained"
            onClick={() => setModalOpen(true)}
            endIcon={<FontAwesome icon={faSquarePlus} width={16} />}
          >
            Ajouter Un Point
          </AddButton>
        </ConditionalComponent>
      </Stack>

      <ConditionalComponent isValid={hasChanges}>
        <Box sx={errorAlertStyles}>
          <FontAwesome
            icon={faCircleExclamation}
            color={'error.main'}
            sx={{ width: 20, height: 20 }}
          />
          <Typography variant="body2" sx={{ color: 'error.dark' }}>
            Des modifications ont été apportées (horaire ou ordre des points). Veuillez recalculer
            le trajet pour appliquer les modifications.
          </Typography>
        </Box>
      </ConditionalComponent>

      <DndContext onDragEnd={handleDragEnd}>
        <SortableContext
          items={sortedData.map((item) => item.id)}
          strategy={verticalListSortingStrategy}
        >
          <StyledTableContainer
            sx={{
              maxHeight: '500px',
            }}
          >
            <Table stickyHeader>
              <TableHead>
                <BaseStyledRow>
                  {tableHead.map((headCell) => (
                    <HeaderCell
                      sx={{
                        backgroundColor: 'primary.lighter',
                        py: 1.5,
                        textAlign: 'center',
                      }}
                      key={headCell.id}
                    >
                      {headCell.label}
                    </HeaderCell>
                  ))}
                </BaseStyledRow>
              </TableHead>
              <TableBody>
                <ConditionalComponent
                  isValid={!loading}
                  defaultComponent={
                    <TableRow>
                      <TableCell colSpan={tableHead.length + 1} align="center" sx={{ py: 3 }}>
                        <CircularProgress size={40} />
                      </TableCell>
                    </TableRow>
                  }
                >
                  {sortedData.map((row) => renderRow(row))}
                </ConditionalComponent>
              </TableBody>
            </Table>
          </StyledTableContainer>
        </SortableContext>
      </DndContext>
      <JourneySummary
        distance={`${trajet.distanceKm || '0.00'} km`}
        duration={`${trajet.duration || '0'}`}
        trafficDate="--/--/----"
        trafficTime={trajet.tripHour}
        isDrawerElement={isDrawerElement}
      />
      <Box
        sx={{ height: '460px', width: '100%', mt: 2, border: '1px solid #e0e0e0', borderRadius: 1 }}
      >
        <ConditionalComponent isValid={reactiveMapRoutes.length > 0}>
          <MapView
            height="460px"
            width="100%"
            Submodule={MapType.CIRCUIT}
            routes={reactiveMapRoutes}
            markers={mapMarkers}
            defaultCenter={{ lat: 43.2965, lng: 5.3798 }}
            defaultZoom={14}
            options={{
              zoomControl: true,
              streetViewControl: false,
              mapTypeControl: false,
              fullscreenControl: true,
              styles: [
                {
                  featureType: 'poi',
                  elementType: 'labels',
                  stylers: [{ visibility: 'off' }],
                },
              ],
            }}
          />
        </ConditionalComponent>
        <ConditionalComponent isValid={reactiveMapRoutes.length === 0}>
          <>Loading map... </>
        </ConditionalComponent>
      </Box>
      <AddPointModal
        open={modalOpen}
        onClose={() => setModalOpen(false)}
        reactiveMapRoutes={reactiveMapRoutes}
        mapMarkers={mapMarkers}
        weeklySchedules={trajet.weeklySchedules || []}
        tripId={trajetId}
        displayNewTrip={displayNewTrip}
      />
    </Box>
  );
}
