import { describe, expect, it } from "vitest"
import { midpoint, projectOntoAxis } from "./hole-geometry"

// Testrigg: en rein nord-sør-akse (tee i sør, green 200 m rett nord) --
// lett å regne fasit for. 111_320 m per breddegrad er samme tilnærming
// som geo.test.ts allerede bruker.
const METERS_PER_DEGREE_LAT = 111_320
const tee = { lat: 59.9, lng: 10.75 }
const green = { lat: 59.9 + 200 / METERS_PER_DEGREE_LAT, lng: 10.75 }

describe("projectOntoAxis", () => {
  it("punktet på start (tee) gir alongPercent=0, crossMeters≈0", () => {
    const { alongPercent, crossMeters } = projectOntoAxis(tee, green, tee)
    expect(alongPercent).toBeCloseTo(0, 3)
    expect(crossMeters).toBeCloseTo(0, 3)
  })

  it("punktet på slutt (green) gir alongPercent=100, crossMeters≈0", () => {
    const { alongPercent, crossMeters } = projectOntoAxis(tee, green, green)
    expect(alongPercent).toBeCloseTo(100, 0)
    expect(crossMeters).toBeCloseTo(0, 1)
  })

  it("midtpunktet på aksen gir alongPercent≈50, crossMeters≈0", () => {
    const mid = midpoint(tee, green)
    const { alongPercent, crossMeters } = projectOntoAxis(tee, green, mid)
    expect(alongPercent).toBeCloseTo(50, 0)
    expect(crossMeters).toBeCloseTo(0, 1)
  })

  it("et punkt rett øst for midtpunktet gir riktig crossMeters mot høyre", () => {
    // Aksen peker rett nord (bearing 0) -- et punkt rett øst for et punkt
    // PÅ aksen skal derfor ligge til HØYRE (positiv cross), på samme
    // langs-posisjon (alongPercent uendret).
    const mid = midpoint(tee, green)
    const offsetEast = { lat: mid.lat, lng: mid.lng + 20 / (METERS_PER_DEGREE_LAT * Math.cos((mid.lat * Math.PI) / 180)) }
    const { alongPercent, crossMeters } = projectOntoAxis(tee, green, offsetEast)
    expect(alongPercent).toBeCloseTo(50, 0)
    expect(crossMeters).toBeGreaterThan(19)
    expect(crossMeters).toBeLessThan(21)
  })

  it("et punkt rett vest for midtpunktet gir negativ crossMeters (venstre)", () => {
    const mid = midpoint(tee, green)
    const offsetWest = { lat: mid.lat, lng: mid.lng - 20 / (METERS_PER_DEGREE_LAT * Math.cos((mid.lat * Math.PI) / 180)) }
    const { crossMeters } = projectOntoAxis(tee, green, offsetWest)
    expect(crossMeters).toBeLessThan(-19)
    expect(crossMeters).toBeGreaterThan(-21)
  })

  it("et punkt bak tee (før start) gir negativ alongPercent", () => {
    const behindTee = { lat: tee.lat - 50 / METERS_PER_DEGREE_LAT, lng: tee.lng }
    const { alongPercent } = projectOntoAxis(tee, green, behindTee)
    expect(alongPercent).toBeLessThan(0)
  })

  it("et punkt forbi green gir alongPercent > 100", () => {
    const beyondGreen = { lat: green.lat + 50 / METERS_PER_DEGREE_LAT, lng: green.lng }
    const { alongPercent } = projectOntoAxis(tee, green, beyondGreen)
    expect(alongPercent).toBeGreaterThan(100)
  })

  it("axisStart == axisEnd degraderer grasiøst (ingen NaN/deling på null)", () => {
    const { alongPercent, crossMeters } = projectOntoAxis(tee, tee, green)
    expect(Number.isFinite(alongPercent)).toBe(true)
    expect(Number.isFinite(crossMeters)).toBe(true)
  })
})

describe("midpoint", () => {
  it("midtpunktet av et punkt med seg selv er punktet selv", () => {
    expect(midpoint(tee, tee)).toEqual(tee)
  })

  it("midtpunktet ligger halvveis mellom to punkt", () => {
    const m = midpoint(tee, green)
    expect(m.lat).toBeCloseTo((tee.lat + green.lat) / 2, 10)
    expect(m.lng).toBeCloseTo((tee.lng + green.lng) / 2, 10)
  })
})
