import * as geolib from 'geolib';
import Parser from '../parser.ts';
import { computeSpeed } from '../utils/computeSpeed.ts';

export const TerminatorsTF = (
  leg: TFTerminalEntry,
  previousFix: NavFix,
  lastCourse: number,
  waypoint?: Waypoint
): [NavFix?, LineSegment[]?] => {
  const targetFix: NavFix = {
    latitude: leg.WptLat,
    longitude: leg.WptLon,
    name: waypoint?.Ident ?? undefined,
    isFlyOver: leg.IsFlyOver,
    altitude: leg.Alt ? leg.Alt.parseAltitude() : previousFix.altitude,
    speed: computeSpeed(leg, previousFix),
    speedConstraint: leg.SpeedLimit,
    altitudeConstraint: leg.Alt,
  };

  const line: LineSegment[] = [[previousFix.longitude, previousFix.latitude]];

  const trackIntoEndpoint = geolib.getGreatCircleBearing(previousFix, targetFix);

  if (previousFix.isFlyOver) {
    let crsIntoEndpoint = trackIntoEndpoint;

    // Check if there even is an arc
    if (crsIntoEndpoint !== lastCourse) {
      // Turn Dir
      if (!leg.TurnDir || leg.TurnDir === 'E') {
        let prov = lastCourse - crsIntoEndpoint;
        prov = prov > 180 ? prov - 360 : prov <= -180 ? prov + 360 : prov;
        leg.TurnDir = prov > 0 ? 'L' : 'R';
      }

      // Generate arc
      let condition = false;
      do {
        if (leg.TurnDir === 'R') {
          const delta = (crsIntoEndpoint - lastCourse).normaliseDegrees();
          lastCourse += delta < 1 ? delta : 1;
          lastCourse = lastCourse.normaliseDegrees();
        } else {
          const delta = (lastCourse - crsIntoEndpoint).normaliseDegrees();
          lastCourse -= delta < 1 ? delta : 1;
          lastCourse = lastCourse.normaliseDegrees();
        }

        const arcFix = geolib.computeDestinationPoint(
          {
            latitude: line.at(-1)![1],
            longitude: line.at(-1)![0],
          },
          ((previousFix.speed ? previousFix.speed : Parser.AC_SPEED) / 3600).toMetre(),
          lastCourse
        );

        line.push([arcFix.longitude, arcFix.latitude]);

        crsIntoEndpoint = geolib.getGreatCircleBearing(arcFix, targetFix);

        if (leg.TurnDir === 'R') {
          condition = crsIntoEndpoint > trackIntoEndpoint;
        } else {
          condition = crsIntoEndpoint < trackIntoEndpoint;
        }
      } while (condition);
    }
  }

  line.push([targetFix.longitude, targetFix.latitude]);

  return [targetFix, line];
};
