import BrowserImageManipulation from 'browser-image-manipulation';
import L from 'leaflet';
import type { Chart as NGChart } from 'navigraph/charts';
import { useCallback, useEffect, useState, type Dispatch, type FC, type SetStateAction } from 'react';
import { charts } from '../lib/navigraph';
import { Loader } from './Loader';

interface SidebarProps {
  airport: Airport;
  runway: Runway;
  terminal: Terminal;
  transitions: Procedure[];
  transition: Procedure | undefined;
  chart: Chart | undefined;
  setTransition: Dispatch<SetStateAction<SidebarProps['transition']>>;
  setChart: Dispatch<SetStateAction<SidebarProps['chart']>>;
  backAction: () => void;
}

export const Sidebar: FC<SidebarProps> = ({
  airport,
  runway,
  terminal,
  transitions,
  transition,
  chart,
  setTransition,
  setChart,
  backAction,
}) => {
  const [inFlight, setInFlight] = useState(false);
  const [chartIndex, setChartIndex] = useState<{
    sid: NGChart[];
    star: NGChart[];
    iap: NGChart[];
  }>({ star: [], sid: [], iap: [] });

  useEffect(() => {
    setInFlight(true);
    (async () => {
      const _chartIndex = await charts.getChartsIndex({ icao: airport.ICAO, version: 'STD' });

      const newChartIndex = {
        star:
          _chartIndex?.filter(
            (_chart) =>
              _chart.category === 'ARR' && (_chart.runways.length === 0 || _chart.runways.includes(runway.Ident))
          ) ?? [],
        sid:
          _chartIndex?.filter(
            (_chart) =>
              _chart.category === 'DEP' && (_chart.runways.length === 0 || _chart.runways.includes(runway.Ident))
          ) ?? [],
        iap:
          _chartIndex?.filter(
            (_chart) =>
              _chart.category === 'APP' && (_chart.runways.length === 0 || _chart.runways.includes(runway.Ident))
          ) ?? [],
      };

      _chartIndex?.filter((_chart) => ['ARR', 'DEP', 'APP'].includes(_chart.category));
      setChartIndex(newChartIndex);
      setInFlight(false);
    })();
  }, [airport.ICAO]);

  useEffect(() => {
    if (terminal) {
      const star = chartIndex.star.find((_chart) => _chart.procedures.includes(terminal.FullName));
      const sid = chartIndex.sid.find((_chart) => _chart.procedures.includes(terminal.FullName));
      const iap = chartIndex.iap.find((_chart) => _chart.procedures.includes(terminal.FullName));
      if (star) findChart(star);
      if (sid) findChart(sid);
      if (iap) findChart(iap);
    }
  }, [terminal, chartIndex]);

  const findChart = useCallback(
    async (_chart: NGChart) => {
      if (chart?.index_number === _chart.index_number) return;
      if (!_chart.bounding_boxes) return;

      const planView = _chart.bounding_boxes.planview;

      const chartImage = await charts.getChartImage({ chart: _chart, theme: 'light' });
      if (!chartImage) return;
      // Crop
      const dataURL = await new BrowserImageManipulation()
        .loadBlob(chartImage)
        .crop(
          planView.pixels.x2 - planView.pixels.x1,
          planView.pixels.y1 - planView.pixels.y2,
          planView.pixels.x1,
          planView.pixels.y2
        )
        .saveAsImage();

      const bounds = new L.LatLngBounds(
        [planView.latlng.lat1, planView.latlng.lng1],
        [planView.latlng.lat2, planView.latlng.lng2]
      );

      setChart({ data: dataURL, index_number: _chart.index_number, bounds });
    },
    [chart]
  );

  return (
    <div className="flex h-full w-[300px] shrink-0 flex-col overflow-hidden">
      <button
        className="sticky top-0 m-2 cursor-pointer rounded border border-red-500 bg-red-500 px-2 py-1 font-semibold text-stone-50 focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black"
        onClick={backAction}
      >
        Go back
      </button>

      <div className="flex h-[calc(100%-50px)] flex-col gap-2 overflow-y-auto px-2 pb-2">
        <div className="flex flex-col gap-2">
          <div className="sticky top-0 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">
            Transitions for <span className="font-bold">{terminal.FullName}</span>
          </div>
          {transitions.map((_procedure) => (
            <button
              key={_procedure.name}
              className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${_procedure.name === transition?.name ? 'outline-2' : ''}`}
              onClick={() => {
                if (_procedure.name === transition?.name) return;

                setTransition(_procedure);
              }}
            >
              {_procedure.name ? _procedure.name : 'NONE'}
            </button>
          ))}
        </div>

        <div className="flex flex-col gap-2">
          <div className="sticky top-0 z-10 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Charts</div>
          {inFlight && <Loader size={3} />}

          <div className="flex flex-col gap-2">
            <div className="sticky top-7 -mx-2 -mt-2 bg-gray-500 px-2 text-lg font-semibold text-white">Arrivals</div>
            {chartIndex.star
              .filter((_chart) => _chart.is_georeferenced)
              .map((_chart) => (
                <button
                  key={_chart.index_number}
                  className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`}
                  onClick={() => findChart(_chart)}
                >
                  <span className="font-bold">{_chart.index_number}</span>
                  <br />
                  {_chart.name}
                </button>
              ))}
          </div>

          <div className="flex flex-col gap-2">
            <div className="sticky top-7 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Departures</div>
            {chartIndex.sid
              .filter((_chart) => _chart.is_georeferenced)
              .map((_chart) => (
                <button
                  key={_chart.index_number}
                  className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`}
                  onClick={() => findChart(_chart)}
                >
                  <span className="font-bold">{_chart.index_number}</span>
                  <br />
                  {_chart.name}
                </button>
              ))}
          </div>

          <div className="flex flex-col gap-2">
            <div className="sticky top-7 -mx-2 bg-gray-500 px-2 text-lg font-semibold text-white">Approaches</div>
            {chartIndex.iap
              .filter((_chart) => _chart.is_georeferenced)
              .map((_chart) => (
                <button
                  key={_chart.index_number}
                  className={`cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 text-left font-semibold focus:outline-2 focus:outline-black focus-visible:outline-2 focus-visible:outline-black ${chart?.index_number === _chart.index_number ? 'outline-2' : ''}`}
                  onClick={() => findChart(_chart)}
                >
                  <span className="font-bold">{_chart.index_number}</span>
                  <br />
                  {_chart.name}
                </button>
              ))}
          </div>
        </div>
      </div>
    </div>
  );
};
