import { createRef, useMemo, useState, type Dispatch, type FC, type SetStateAction } from 'react';
import Parser from '../parser/parser';
import { Loader } from './Loader';

interface ProcedureSelectProps {
  parser: Parser;
  selectedAirport: Airport | undefined;
  selectedRunway: Runway | undefined;
  selectedTerminal: Terminal | undefined;
  setSelectedAirport: Dispatch<SetStateAction<Airport | undefined>>;
  setSelectedRunway: Dispatch<SetStateAction<Runway | undefined>>;
  setSelectedTerminal: Dispatch<SetStateAction<Terminal | undefined>>;
  handleSelection: (transitions: string[], terminal: Terminal) => void;
}

export const ProcedureSelect: FC<ProcedureSelectProps> = ({
  parser,
  selectedAirport,
  selectedRunway,
  selectedTerminal,
  setSelectedAirport,
  setSelectedRunway,
  setSelectedTerminal,
  handleSelection,
}) => {
  const inputRef = createRef<HTMLInputElement>();
  const [error, setError] = useState<string>();
  const [inFlight, setInFlight] = useState<number>();

  const runways = useMemo(
    () => parser.runways.filter(({ AirportID }) => AirportID === selectedAirport?.ID),
    [selectedAirport]
  );
  const terminals = useMemo(() => {
    const _terminals = parser.terminals.filter(
      ({ AirportID, RwyID }) => AirportID === selectedAirport?.ID && (!RwyID || RwyID === selectedRunway?.ID)
    );

    return {
      star: _terminals.filter((terminal) => terminal.Proc === 1),
      sid: _terminals.filter((terminal) => terminal.Proc === 2),
      iap: _terminals.filter((terminal) => terminal.Proc === 3),
    };
  }, [selectedAirport, selectedRunway]);

  return (
    <div className="flex h-full w-[300px] shrink-0 flex-col overflow-hidden">
      {selectedAirport && (
        <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={() => {
            setError(undefined);
            setInFlight(undefined);

            if (selectedTerminal) {
              setSelectedTerminal(undefined);
            } else if (selectedRunway) {
              setSelectedRunway(undefined);
            } else if (selectedAirport) {
              setSelectedAirport(undefined);
            }
          }}
        >
          Go back
        </button>
      )}

      <div className="flex h-[calc(100%-50px)] flex-col gap-2 overflow-y-auto px-2 pb-2">
        {!selectedAirport && (
          <div className="flex w-full flex-col gap-2">
            <h1 className="text-center text-3xl">Enter Airport ICAO</h1>
            <input
              ref={inputRef}
              className="rounded border border-black px-2 py-1 focus:outline-2 focus-visible:outline-2"
              onChange={(e) => {
                if (e.target.value.length <= 4) e.target.value = e.target.value.toUpperCase();
                else e.target.value = e.target.value.slice(0, 4);
              }}
            ></input>
            <button
              className="w-full cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2"
              onClick={() => {
                const airport = parser.airports.find(({ ICAO }) => ICAO === inputRef.current?.value.toUpperCase());
                if (!airport) {
                  setError('Airport not found');
                  return;
                }
                setSelectedAirport(airport);
                setError(undefined);
              }}
            >
              Select Airport
            </button>
            {error && <span className="text-center text-red-700">{error}</span>}
          </div>
        )}

        {selectedAirport && !selectedRunway && (
          <div className="flex w-full flex-col gap-2">
            <h1 className="text-center text-3xl">Select Runway</h1>
            {runways.map((runway) => (
              <button
                key={runway.ID}
                className="w-full cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2"
                onClick={() => setSelectedRunway(runway)}
              >
                Runway {runway.Ident}
              </button>
            ))}
          </div>
        )}

        {selectedAirport && selectedRunway && !selectedTerminal && (
          <div className="flex w-full flex-col gap-2">
            <h1 className="text-center text-3xl">Select Procedure</h1>

            <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">Arrivals</div>
              {terminals.star.map((terminal) => (
                <button
                  key={terminal.ID}
                  className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100"
                  onClick={() => {
                    setInFlight(terminal.ID);
                    parser.loadTerminal(terminal.ID).then(() => {
                      setSelectedTerminal(terminal);
                      const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
                      handleSelection(Array.from(transitions), terminal);
                      setInFlight(undefined);
                    });
                  }}
                  disabled={!!inFlight}
                >
                  <div className="flex justify-between">
                    {terminal.FullName}
                    {inFlight === terminal.ID && <Loader size={0.5} />}
                  </div>
                </button>
              ))}
            </div>
            <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">Departures</div>
              {terminals.sid.map((terminal) => (
                <button
                  key={terminal.ID}
                  className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100"
                  onClick={() => {
                    setInFlight(terminal.ID);
                    parser.loadTerminal(terminal.ID).then(() => {
                      setSelectedTerminal(terminal);
                      const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
                      handleSelection(Array.from(transitions), terminal);
                      setInFlight(undefined);
                    });
                  }}
                  disabled={!!inFlight}
                >
                  <div className="flex justify-between">
                    {terminal.FullName}
                    {inFlight === terminal.ID && <Loader size={0.5} />}
                  </div>
                </button>
              ))}
            </div>
            <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">Approaches</div>
              {terminals.iap.map((terminal) => (
                <button
                  key={terminal.ID}
                  className="cursor-pointer rounded border border-gray-300 bg-gray-300 px-2 py-1 font-semibold focus:outline-2 focus-visible:outline-2 disabled:bg-gray-100"
                  onClick={() => {
                    setInFlight(terminal.ID);
                    parser.loadTerminal(terminal.ID).then(() => {
                      setSelectedTerminal(terminal);
                      const transitions = new Set(parser.procedures.map((proc) => proc.Transition));
                      handleSelection(Array.from(transitions), terminal);
                      setInFlight(undefined);
                    });
                  }}
                  disabled={!!inFlight}
                >
                  <div className="flex justify-between">
                    {terminal.FullName}
                    {inFlight === terminal.ID && <Loader size={0.5} />}
                  </div>
                </button>
              ))}
            </div>
          </div>
        )}
      </div>
    </div>
  );
};
