import { useEffect, useState } from 'react';
import { Droppable, Draggable } from '@hello-pangea/dnd';
import Button from '@mui/material/Button';
import { FaTrash, FaEdit } from 'react-icons/fa';
import AltitudeDialog from './AltitudeDialog';
import './PointsList.css';
import { newGuid } from '../utils';
import { useLanguage } from './LanguageContext';
import { translations } from '../constants/translations';
import { calculateBatteryPercentUsed } from '../services/calculateBatteryUsage';
import { calculateDistance } from '../services/calculateDistance';
import type { FlightPoint, CalculatedPointInfo, AircraftParams } from '../types';

interface PointsListProps {
  points: FlightPoint[];
  calculatedPointInfo: CalculatedPointInfo[];
  setCalculatedPointInfo: React.Dispatch<React.SetStateAction<CalculatedPointInfo[]>>;
  setPoints: React.Dispatch<React.SetStateAction<FlightPoint[]>>;
  removePoint: (id: string) => void;
  aircraft: AircraftParams | null;
  initialAltitude: number;
}

export default function PointsList({
  points,
  calculatedPointInfo,
  setCalculatedPointInfo,
  setPoints,
  removePoint,
  aircraft,
  initialAltitude,
}: PointsListProps) {
  const { targetLanguage } = useLanguage();
  const t = translations[targetLanguage];
  const [openDialog, setOpenDialog] = useState(false);
  const [currentPoint, setCurrentPoint] = useState<FlightPoint | null>(null);
  const [isEditMode, setIsEditMode] = useState(false);
  const [isCalculated, setIsCalculated] = useState(true);

  useEffect(() => {
    setIsCalculated(false);

    const calculatePoints = async () => {
      const calculatedData = await calculateBatteryUsageForPoints(points);
      setCalculatedPointInfo([...calculatedData]);
      setIsCalculated(true);
    };

    calculatePoints();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [points]);

  const calculateBatteryUsageForPoints = async (pts: FlightPoint[]): Promise<CalculatedPointInfo[]> => {
    const pointsInfo: CalculatedPointInfo[] = [{
      bat: 100,
      time: 0,
    }];

    if (!aircraft) return pointsInfo;

    for (let index = 1; index < pts.length; index++) {
      const point1 = pts[index - 1];
      const point2 = pts[index];

      const midPoint = {
        lat: (point1.position.lat + point2.position.lat) / 2,
        lon: (point1.position.lng + point2.position.lng) / 2,
      };

      const distance = calculateDistance(point1, point2, aircraft.type, initialAltitude, aircraft.downang, aircraft.upang);
      const time = distance / aircraft.speed;

      const percent = await calculateBatteryPercentUsed(aircraft.speed, time, midPoint);
      pointsInfo.push({
        bat: pointsInfo[index - 1].bat - percent,
        time: pointsInfo[index - 1].time + time,
      });
    }
    return pointsInfo;
  };

  const handleDialogOpen = (point: FlightPoint | null = null) => {
    setIsEditMode(!!point);
    setCurrentPoint(point || { id: '', position: { lat: 0, lng: 0 }, altitude: 0, meta: [] });
    setOpenDialog(true);
  };

  const handleDialogClose = () => {
    setOpenDialog(false);
    setCurrentPoint(null);
  };

  const handleAltitudeSubmit = () => {
    if (!currentPoint) return;

    if (isEditMode) {
      setPoints((prevPoints) =>
        prevPoints.map((point) =>
          point.id === currentPoint.id ? currentPoint : point
        )
      );
    } else {
      setPoints((prevPoints) => [
        ...prevPoints,
        { ...currentPoint, id: newGuid() },
      ]);
    }
    handleDialogClose();
  };

  return (
    <>
      <Droppable droppableId="points">
        {(provided) => (
          <div
            {...provided.droppableProps}
            ref={provided.innerRef}
            className="flight-plan-points-container"
          >
            {points.map((point, index) => (
              <Draggable key={point.id} draggableId={point.id} index={index}>
                {(provided) => (
                  <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                    className={'flight-plan-point'}
                  >
                    <div className={isCalculated ? 'point-details' : 'point-details uncalculated'}>
                      <strong>{t.point} {index < 9 ? `0${index + 1}` : index + 1}: </strong>
                      {point.altitude}{t.metres} {Math.floor(calculatedPointInfo[index]?.bat)}%{t.battery} {Math.floor(calculatedPointInfo[index]?.time)}{t.hour}
                      {Math.floor((calculatedPointInfo[index]?.time - Math.floor(calculatedPointInfo[index]?.time)) * 60)}{t.minutes}
                    </div>
                    <div className="point-actions">
                      <Button
                        className="icon"
                        onClick={() => handleDialogOpen(point)}
                        size="small"
                        color="primary"
                        startIcon={<FaEdit className='small-icon' />}
                      />
                      <Button
                        className="icon"
                        onClick={() => removePoint(point.id)}
                        size="small"
                        color="error"
                        startIcon={<FaTrash className='small-icon' />}
                      />
                    </div>
                  </div>
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>

      {openDialog && currentPoint && (
        <AltitudeDialog
          openDialog={openDialog}
          handleDialogClose={handleDialogClose}
          handleAltitudeSubmit={handleAltitudeSubmit}
          altitude={currentPoint.altitude}
          setAltitude={(altitude) =>
            setCurrentPoint((prev) => prev ? { ...prev, altitude: Number(altitude) } : prev)
          }
          latitude={currentPoint.position.lat}
          setLatitude={(latitude) =>
            setCurrentPoint((prev) => prev ? {
              ...prev,
              position: { ...prev.position, lat: Number(latitude) },
            } : prev)
          }
          longitude={currentPoint.position.lng}
          setLongitude={(longitude) =>
            setCurrentPoint((prev) => prev ? {
              ...prev,
              position: { ...prev.position, lng: Number(longitude) },
            } : prev)
          }
          meta={currentPoint.meta || []}
          setMeta={(meta) => setCurrentPoint((prev) => prev ? { ...prev, meta } : prev)}
          isEditMode={isEditMode}
        />
      )}
    </>
  );
}
