///|
fn globe_point(
  point_id : String,
  label : String,
  latitude_deg : Double,
  longitude_deg : Double,
  role : String,
  status : String,
) -> GlobeOverlayPoint {
  { point_id, label, latitude_deg, longitude_deg, role, status }
}

///|
fn signed_site_latitude(site : @core.LunarSite, row_offset : Int) -> Double {
  let offset = 0.0 - row_offset.to_double()
  let span = if offset >= 0.0 {
    site.bounds.north_deg - site.center.latitude_deg
  } else {
    site.center.latitude_deg - site.bounds.south_deg
  }
  site.center.latitude_deg + offset / 16.0 * span
}

///|
fn signed_site_longitude(site : @core.LunarSite, col_offset : Int) -> Double {
  let offset = col_offset.to_double()
  let span = if offset >= 0.0 {
    site.bounds.east_deg - site.center.longitude_deg
  } else {
    site.center.longitude_deg - site.bounds.west_deg
  }
  site.center.longitude_deg + offset / 16.0 * span
}

///|
fn selected_corridor_window(
  windows : Array[@mission.CorridorScanWindow],
  selected_route_id : String,
) -> @mission.CorridorScanWindow {
  let mut picked = windows[0]
  for window in windows {
    if window.selected_route_id == selected_route_id &&
      (
        picked.selected_route_id != selected_route_id ||
        window.rank < picked.rank
      ) {
      picked = window
    }
  }
  picked
}

///|
fn site_footprint(site : @core.LunarSite) -> Array[GlobeOverlayPoint] {
  [
    globe_point(
      "site-footprint/sw",
      "southwest bound",
      site.bounds.south_deg,
      site.bounds.west_deg,
      "footprint",
      "measured",
    ),
    globe_point(
      "site-footprint/nw",
      "northwest bound",
      site.bounds.north_deg,
      site.bounds.west_deg,
      "footprint",
      "measured",
    ),
    globe_point(
      "site-footprint/ne",
      "northeast bound",
      site.bounds.north_deg,
      site.bounds.east_deg,
      "footprint",
      "measured",
    ),
    globe_point(
      "site-footprint/se",
      "southeast bound",
      site.bounds.south_deg,
      site.bounds.east_deg,
      "footprint",
      "measured",
    ),
  ]
}

///|
fn selected_route_trace(
  site : @core.LunarSite,
  window : @mission.CorridorScanWindow,
  selected_route_id : String,
) -> GlobeOverlayPath {
  let end_lat = signed_site_latitude(site, window.row_offset)
  let end_lon = signed_site_longitude(site, window.col_offset)
  let mid_lat = (site.center.latitude_deg + end_lat) / 2.0
  let mid_lon = (site.center.longitude_deg + end_lon) / 2.0
  {
    path_id: "globe-route/\{selected_route_id}",
    label: selected_route_id,
    kind: "selected-route",
    status: @mission.corridor_scan_window_status_label(window),
    points: [
      globe_point(
        "route/\{selected_route_id}/start",
        "trusted square center",
        site.center.latitude_deg,
        site.center.longitude_deg,
        "route-start",
        "measured",
      ),
      globe_point(
        "route/\{selected_route_id}/mid",
        "corridor approach",
        mid_lat,
        mid_lon,
        "route-mid",
        "derived",
      ),
      globe_point(
        "route/\{selected_route_id}/window",
        window.window_id,
        end_lat,
        end_lon,
        "route-window",
        @mission.corridor_scan_window_status_label(window),
      ),
    ],
  }
}

///|
fn globe_corridor_window(
  site : @core.LunarSite,
  selected_route_id : String,
  window : @mission.CorridorScanWindow,
) -> GlobeOverlayWindow {
  {
    window_id: window.window_id,
    rank: window.rank,
    row_offset: window.row_offset,
    col_offset: window.col_offset,
    latitude_deg: signed_site_latitude(site, window.row_offset),
    longitude_deg: signed_site_longitude(site, window.col_offset),
    decision: @mission.corridor_scan_window_status_label(window),
    selected: window.selected_route_id == selected_route_id,
    selected_route_id: window.selected_route_id,
    max_neighbor_grade: window.max_neighbor_grade,
    roughness_m: window.roughness_m,
  }
}

///|
fn globe_corridor_windows(
  site : @core.LunarSite,
  windows : Array[@mission.CorridorScanWindow],
  selected_route_id : String,
) -> Array[GlobeOverlayWindow] {
  windows.map(window => globe_corridor_window(site, selected_route_id, window))
}

///|
fn hardware_authority(blocker_count : Int) -> String {
  if blocker_count > 0 {
    "hardware denied"
  } else {
    "operator review"
  }
}

///|
fn globe_overlay(
  dossier : @site.SiteDossier,
  grid : @terrain.TerrainGrid,
  selected_route_id : String,
) -> GlobeOverlayView {
  let selected_window = selected_corridor_window(
    dossier.corridor_scan,
    selected_route_id,
  )
  let trace = selected_route_trace(
    dossier.site,
    selected_window,
    selected_route_id,
  )
  let blocker_count = dossier.blockers.length()
  {
    overlay_id: "globe-overlay/\{dossier.site.site_id}",
    source_dataset_id: grid.source_manifest.dataset_id,
    source_path: grid.source_manifest.source_path,
    claim: "projected site bounds and promoted route window for browser globe context",
    footprint: site_footprint(dossier.site),
    selected_route_trace: trace,
    corridor_windows: globe_corridor_windows(
      dossier.site,
      dossier.corridor_scan,
      selected_route_id,
    ),
    hardware_authority: hardware_authority(blocker_count),
    blocker_count,
    status: trace.status,
    summary: "trusted square bounds, 81 measured corridor windows, and \{selected_route_id} route window projected from MoonBit view-model data",
  }
}