import FontAwesome from '@/shared/components/fontawesome';
import SvgColor from '@/shared/components/svg-color';
import { AddButton, ColumnButton, outlinedColor } from '@/shared/components/table/styles';
import CustomTooltip from '@/shared/components/tooltips/tooltip-custom';
import { iconButtonStyles, StyledTableContainer } from '@/shared/theme/css';
import { faCopy, faSquarePlus, faUser } from '@fortawesome/free-solid-svg-icons';
import { IconButton, Table, TableBody, TableCell, TableHead } from '@mui/material';
import { Box, Stack } from '@mui/system';
import React, { useEffect, useState, useCallback } from 'react';
import { DirectionsRenderer } from '@react-google-maps/api';

import { ISuiviTrajet, PointType } from '@/shared/types/trajet';
import { TableConfig, useTableManager } from '@/hooks/use-table-manager';
import { _suiviTrajet } from '@/shared/_mock/_trajets';
import dynamic from 'next/dynamic';
import { DndContext, DragEndEvent } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy, arrayMove, useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { JourneySummary } from '@/shared/components/google-maps/journey-summary';
import { MapType, RouteMarker } from '@/shared/types/Maps';
import { HeaderCell } from '@/shared/components/form/style';
import { useTrajetStore } from '@/shared/api/stores/trajetStore';
import AddPointModal from './add-point-modal';
import { StatusColor } from '@/shared/sections/chauffeur/planingChauffeur/utils/schedule-utils';
import { BaseStyledRow, TrajetStyledRow } from '../../contract/styles';
import ConditionalComponent from '@/shared/components/table/ConditionalComponent';
import { enqueueSnackbar } from 'notistack';

const MapView = dynamic(() => import('@/shared/components/google-maps/mapsPoints'), {
  ssr: false,
});
interface TrajetFormProps {
  mode: string;
  isDrawerElement?: boolean;
  onAddPoint: () => void;
  trajetId?: string;
}
const DEFAULT_SUIVIT_TRAJET_TABLE_HEAD = [
  { id: 'tripId', label: 'N° trajet', align: 'left' as const },
  { id: 'nom', label: 'Nom & adresse', align: 'left' as const },
  { id: 'horaire', label: 'Horaire', align: 'center' as const },
  { id: 'km', label: 'Km', align: 'center' as const },
  { id: 'tps', label: 'Tps (sec)', align: 'center' as const },
  { id: 'gps', label: 'Gps', align: 'center' as const }
];

const suiviTrajetConfig: TableConfig<ISuiviTrajet> = {
  initialData: _suiviTrajet,
  defaultTableHead: DEFAULT_SUIVIT_TRAJET_TABLE_HEAD,
};



export default function DetailsTrajet({ mode, isDrawerElement, onAddPoint, trajetId }: TrajetFormProps) {
  const { suiviTrajets, fetchSuiviTrajets, updateSuiviTrajets } = useTrajetStore();
  const {
    table,
    filteredData,
    tableHead,
  } = useTableManager<ISuiviTrajet>(suiviTrajetConfig);
  const [sortedData, setSortedData] = useState<ISuiviTrajet[]>([]);
  const [mapMarkers, setMapMarkers] = useState<RouteMarker[]>([]);
  const [directionsResult, setDirectionsResult] = useState<google.maps.DirectionsResult | null>(null);
  const [mapCenter, setMapCenter] = useState({ lat: 43.296482, lng: 5.369780 });
  const [modalOpen, setModalOpen] = useState(false);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    setSortedData(filteredData);
  }, [filteredData]);

  const getMarkerIcon = useCallback((index: number, total: number) => {
    if (!window.google) return '/assets/icons/maps/dynamic/circuit-point.svg';

    return {
      url: index === 0
        ? '/assets/icons/maps/dynamic/circuit-start.svg'
        : index === total - 1
          ? '/assets/icons/maps/dynamic/circuit-end.svg'
          : '/assets/icons/maps/dynamic/circuit-point.svg',
      scaledSize: new google.maps.Size(32, 32),
      anchor: new google.maps.Point(16, 32)
    };
  }, []);

  const loadTrajetData = useCallback(async () => {
    if (!trajetId) return;
    try {
      const data = await fetchSuiviTrajets(trajetId);
      const suiviData = Array.isArray(data) ? data : [];
      const suiviDataWithPointType = suiviData.map((point) => ({
        ...point,
        pointType: point.pointType || (Math.random() > 0.3 ? PointType.ESTABLISHMENT : PointType.PASSENGER),
      }))

      if (suiviDataWithPointType.length > 0) {
        setSortedData(suiviDataWithPointType)

        const newMarkers = suiviData
          .map((point: ISuiviTrajet, index: number) => {
            const lat = parseFloat(point.gps);
            const lng = parseFloat(point.gps1);

            if (isNaN(lat) || isNaN(lng)) {
              return null;
            }

            return {
              id: point.tripId || `point-${index + 1}`,
              position: { lat, lng },
              title: `${point.nom} - ${point.adresse}`,
              icon: getMarkerIcon(index, suiviData.length),
              color: StatusColor.PRIMARY
            } as RouteMarker;
          })
          .filter((marker): marker is RouteMarker => marker !== null);

        setMapMarkers(newMarkers);
        calculateRoute(newMarkers);
        localStorage.setItem(`trajet_markers_${trajetId}`, JSON.stringify(newMarkers));
      } else {
        setSortedData([]);
        setMapMarkers([]);
        localStorage.removeItem(`trajet_markers_${trajetId}`);
      }
    } catch (error) {
      console.error('Error loading trajet data:', error);
      setSortedData([]);
      setMapMarkers([]);
      localStorage.removeItem(`trajet_markers_${trajetId}`);
      setError((error as Error).message);
    }
  }, [trajetId, fetchSuiviTrajets]);

  const calculateRoute = useCallback(async (markers: RouteMarker[]) => {
    if (!window.google || markers.length < 2) return;

    const directionsService = new google.maps.DirectionsService();
    try {
      const result = await directionsService.route({
        origin: new google.maps.LatLng(markers[0].position.lat, markers[0].position.lng),
        destination: new google.maps.LatLng(
          markers[markers.length - 1].position.lat,
          markers[markers.length - 1].position.lng
        ),
        waypoints: markers.slice(1, -1).map(marker => ({
          location: new google.maps.LatLng(marker.position.lat, marker.position.lng),
          stopover: true
        })),
        travelMode: google.maps.TravelMode.DRIVING,
        optimizeWaypoints: false
      });

      setDirectionsResult(result);
    } catch (error) {
      console.error('Error calculating route:', error);
    }
  }, []);

  useEffect(() => {
    if (trajetId) {
      loadTrajetData();
    }
  }, [trajetId, loadTrajetData]);

  const renderCellContent = (columnId: string, value: any, row: ISuiviTrajet) => {
    switch (columnId) {
      case 'nom':
        return (
          <Stack direction="column" spacing={1} alignItems="flex-start">
            <Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
              <ConditionalComponent isValid={row.pointType === PointType.ESTABLISHMENT}>
                <SvgColor
                  src={"/assets/icons/form/ic_building.svg"}
                  sx={{ color: "primary.main", width: 12, height: 12 }}
                />
              </ConditionalComponent>
              <ConditionalComponent isValid={row.pointType === PointType.PASSENGER}>
                <FontAwesome icon={faUser} width={12} color="primary.main" />
              </ConditionalComponent>
              {value}</Box>
            <Box>{row.adresse}</Box>
          </Stack>
        );
      default:
        return value;
    }
  };

  const SortableTrajetRow = ({ row, selected, onSelectRow, tableHead }: {
    row: ISuiviTrajet;
    selected: boolean;
    onSelectRow: () => void;
    tableHead: any[];
  }) => {

    const {
      attributes,
      listeners,
      setNodeRef,
      transform,
      transition,
    } = useSortable({ id: row.id });

    const style = {
      transform: CSS.Transform.toString(transform),
      transition,
    };

    return (
      <TrajetStyledRow
        style={style}
      >
        {tableHead.map((column: any) => (
          <TableCell
            ref={setNodeRef}
            {...attributes}
            {...listeners}
            key={column.id}
            align={column.align || 'left'}
            sx={{
              whiteSpace: 'nowrap', py: 1,
              cursor: "grab"
            }}
          >
            {renderCellContent(column.id, row[column.id as keyof ISuiviTrajet], row)}
          </TableCell>
        ))}
      </TrajetStyledRow>
    );
  };

  const renderRow = (row: ISuiviTrajet) => {
    return (
      <SortableTrajetRow
        key={row.id}
        row={row}
        selected={table.selected.includes(row.id)}
        onSelectRow={() => table.onSelectRow(row.id)}
        tableHead={tableHead}
      />
    );
  };

  const handleDragEnd = (event: DragEndEvent) => {
    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.pointType === PointType.ESTABLISHMENT && overItem.pointType !== PointType.ESTABLISHMENT) ||
      (activeItem.pointType !== PointType.ESTABLISHMENT && overItem.pointType === PointType.ESTABLISHMENT)) {
        enqueueSnackbar("Les établissements ne peuvent être échangés qu'avec d'autres établissements", { variant: 'warning' });
        return;
      }

      
      const newSortedData = arrayMove(sortedData, oldIndex, newIndex);
      setSortedData(newSortedData);

      const newMarkers = newSortedData
        .map((point, index) => {
          const lat = parseFloat(point.gps);
          const lng = parseFloat(point.gps1);

          if (isNaN(lat) || isNaN(lng)) return null;

          return {
            id: point.tripId || `point-${index + 1}`,
            position: { lat, lng },
            title: `${point.nom} - ${point.adresse}`,
            icon: getMarkerIcon(index, newSortedData.length),
            color: StatusColor.PRIMARY
          } as RouteMarker;
        })
        .filter((marker): marker is RouteMarker => marker !== null);

      setMapMarkers(newMarkers);

      if (trajetId) {
        localStorage.setItem(`trajet_markers_${trajetId}`, JSON.stringify(newMarkers));
        updateSuiviTrajets(trajetId, newSortedData).catch(error => {
          console.error('Error updating suivi trajets:', error);
          setError('Failed to update trip points order');
        });
      }
    }
  };

  const handleCloseModal = () => {
    setModalOpen(false);
  };

  const handlePointAdded = useCallback(async (newPoint: RouteMarker) => {
    const updatedMarkers = [...mapMarkers, newPoint];
    setMapMarkers(updatedMarkers);
    calculateRoute(updatedMarkers);
    await loadTrajetData();
  }, [mapMarkers, calculateRoute, loadTrajetData]);

  return (
    <Box sx={{ width: '100%' }}>
      <Stack flexGrow={0} direction="row" alignItems="center" justifyContent="right" gap={1} py={2}>
        <ConditionalComponent
          isValid={!(mode === "copy" && isDrawerElement)}
        >
          <CustomTooltip title={isDrawerElement ? "Dupliquer le trajet" : "Recopier & Recalculer"} arrow>
            <IconButton size="small" sx={iconButtonStyles}>
              <FontAwesome icon={faCopy} width={16} />
            </IconButton>
          </CustomTooltip>
        </ConditionalComponent>

        <ConditionalComponent
          isValid={!(mode === "view" && isDrawerElement)}
        >
          <ColumnButton
            sx={{ ...outlinedColor }}
            variant="outlined"
            endIcon={
              <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>

      <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>
                {sortedData.map((row) => renderRow(row))}
              </TableBody>
            </Table>
          </StyledTableContainer>
        </SortableContext>
      </DndContext>

      <JourneySummary
        distance={`${sortedData[0]?.km || '0.00'}km`}
        duration={`${sortedData[0]?.tps || '0'} min`}
        trafficDate="06/10/2024"
        trafficTime="10:00:00"
        isDrawerElement={isDrawerElement}
      />

      <Box sx={{ height: '460px', width: '100%', mt: 2, border: '1px solid #e0e0e0', borderRadius: 1 }}>
        <MapView
          height="460px"
          width="100%"
          Submodule={MapType.CIRCUIT}
          routes={[{
            id: trajetId || 'current',
            name: 'Current Route',
            color: StatusColor.PRIMARY,
            path: mapMarkers.map(marker => marker.position),
            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
            }))
          }]}
          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 isValid={!!directionsResult}>
            <DirectionsRenderer
              directions={directionsResult!}
              options={{
                suppressMarkers: true,
                preserveViewport: true,
                polylineOptions: {
                  strokeColor: StatusColor.PRIMARY,
                  strokeOpacity: 0.7,
                  strokeWeight: 5,
                },
              }}
            />
          </ConditionalComponent>
        </MapView>
      </Box>

      <AddPointModal
        open={modalOpen}
        onClose={handleCloseModal}
        trajetId={trajetId || ''}
        onPointAdded={handlePointAdded}
      />
    </Box>
  );
}
