import { lonLatToWorldTile } from '../../utils/projection'
import { worldToScreen, type CameraState } from '../camera/camera'
import { type MapLayer, type LayerRenderContext } from './mapLayer'
import { type MapScene } from '../renderer/mapRenderer'
import { type ScreenPoint } from './trackLayer'
import {
  type OrienteeringCourseControl,
  type OrienteeringCourseFinish,
  type OrienteeringCourseLeg,
  type OrienteeringCourseStart,
} from '../../utils/orienteeringCourse'

export interface ProjectedCourseLeg {
  index: number
  fromKind: OrienteeringCourseLeg['fromKind']
  toKind: OrienteeringCourseLeg['toKind']
  from: ScreenPoint
  to: ScreenPoint
}

export interface ProjectedCourseStart {
  index: number
  label: string
  point: ScreenPoint
  headingDeg: number | null
}

export interface ProjectedCourseControl {
  label: string
  sequence: number
  point: ScreenPoint
}

export interface ProjectedCourseFinish {
  index: number
  label: string
  point: ScreenPoint
}

export interface ProjectedCourseLayers {
  starts: ProjectedCourseStart[]
  controls: ProjectedCourseControl[]
  finishes: ProjectedCourseFinish[]
  legs: ProjectedCourseLeg[]
}

function buildVectorCamera(scene: MapScene): CameraState {
  return {
    centerWorldX: scene.exactCenterWorldX,
    centerWorldY: scene.exactCenterWorldY,
    viewportWidth: scene.viewportWidth,
    viewportHeight: scene.viewportHeight,
    visibleColumns: scene.visibleColumns,
    rotationRad: scene.rotationRad,
  }
}

export class CourseLayer implements MapLayer {
  projectPoint(point: { point: { lon: number; lat: number } }, scene: MapScene, camera: CameraState): ScreenPoint {
    const worldPoint = lonLatToWorldTile(point.point, scene.zoom)
    return worldToScreen(camera, worldPoint, false)
  }

  projectStarts(starts: OrienteeringCourseStart[], scene: MapScene, camera: CameraState): ProjectedCourseStart[] {
    return starts.map((start, index) => ({
      index,
      label: start.label,
      point: this.projectPoint(start, scene, camera),
      headingDeg: start.headingDeg,
    }))
  }

  projectControls(controls: OrienteeringCourseControl[], scene: MapScene, camera: CameraState): ProjectedCourseControl[] {
    return controls.map((control) => ({
      label: control.label,
      sequence: control.sequence,
      point: this.projectPoint(control, scene, camera),
    }))
  }

  projectFinishes(finishes: OrienteeringCourseFinish[], scene: MapScene, camera: CameraState): ProjectedCourseFinish[] {
    return finishes.map((finish, index) => ({
      index,
      label: finish.label,
      point: this.projectPoint(finish, scene, camera),
    }))
  }

  projectLegs(legs: OrienteeringCourseLeg[], scene: MapScene, camera: CameraState): ProjectedCourseLeg[] {
    return legs.map((leg, index) => ({
      index,
      fromKind: leg.fromKind,
      toKind: leg.toKind,
      from: worldToScreen(camera, lonLatToWorldTile(leg.fromPoint, scene.zoom), false),
      to: worldToScreen(camera, lonLatToWorldTile(leg.toPoint, scene.zoom), false),
    }))
  }

  projectCourse(scene: MapScene): ProjectedCourseLayers | null {
    const course = scene.course
    if (!course) {
      return null
    }

    const camera = buildVectorCamera(scene)
    return {
      starts: this.projectStarts(course.layers.starts, scene, camera),
      controls: this.projectControls(course.layers.controls, scene, camera),
      finishes: this.projectFinishes(course.layers.finishes, scene, camera),
      legs: this.projectLegs(course.layers.legs, scene, camera),
    }
  }

  draw(_context: LayerRenderContext): void {}
}
