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

/**
 * @param crsIntoEndpoint Course into arc endpoint
 * @param crsFromOrigin Course from arc origin point
 * @param start Arc origin point
 * @param speed Speed within arc
 * @param turnDir Turn direction
 * @param force360 If true, force a 360° turn
 * @returns Line segments
 */
export const generatePerformanceArc = (
  crsIntoEndpoint: number,
  crsFromOrigin: number,
  start: NavFix,
  speed: number,
  turnDir?: TurnDirection,
  force360?: boolean
) => {
  const turnRate = computeTurnRate(speed, Parser.AC_BANK);
  const originalCrsFromOrigin = crsFromOrigin;

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

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

    // Generate arc
    while (!crsFromOrigin.equal(crsIntoEndpoint)) {
      let time = 0;
      if (turnDir === 'R') {
        const delta = (crsIntoEndpoint - crsFromOrigin).normaliseDegrees();
        const increment = delta < 1 ? delta : 1;
        crsFromOrigin = (crsFromOrigin + increment).normaliseDegrees();
        time = increment / turnRate;
      } else {
        const delta = (crsFromOrigin - crsIntoEndpoint).normaliseDegrees();
        const increment = delta < 1 ? delta : 1;
        crsFromOrigin = (crsFromOrigin - increment).normaliseDegrees();
        time = increment / turnRate;
      }

      const arcFix = geolib.computeDestinationPoint(
        {
          latitude: line.at(-1)![1],
          longitude: line.at(-1)![0],
        },
        ((speed / 3600) * time).toMetre(),
        crsFromOrigin
      );

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

    // Second half
    if (force360) {
      const temp = crsIntoEndpoint;
      crsIntoEndpoint = originalCrsFromOrigin;
      crsFromOrigin = temp;

      while (!crsFromOrigin.equal(crsIntoEndpoint)) {
        let time = 0;
        if (turnDir === 'R') {
          const delta = (crsIntoEndpoint - crsFromOrigin).normaliseDegrees();
          const increment = delta < 1 ? delta : 1;
          crsFromOrigin = (crsFromOrigin + increment).normaliseDegrees();
          time = increment / turnRate;
        } else {
          const delta = (crsFromOrigin - crsIntoEndpoint).normaliseDegrees();
          const increment = delta < 1 ? delta : 1;
          crsFromOrigin = (crsFromOrigin - increment).normaliseDegrees();
          time = increment / turnRate;
        }

        const arcFix = geolib.computeDestinationPoint(
          {
            latitude: line.at(-1)![1],
            longitude: line.at(-1)![0],
          },
          ((speed / 3600) * time).toMetre(),
          crsFromOrigin
        );

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

  return line;
};
