// Copyright (C) 2026 Jason M. Schwefel. All Rights Reserved.
package com.coldboreballisticsllc.scopedope.data.sensor

import org.junit.Assert.assertEquals
import org.junit.Test

/**
 * Tests for [WindBearingConverter.toShooterRelative].
 *
 * Convention: 0° = headwind, 90° = R→L crosswind, 180° = tailwind, 270° = L→R.
 * Input: absolute compass bearing (0–359°), firingAzimuth (0–359°).
 */
class WindBearingConverterTest {

    private val eps = 0.001

    @Test
    fun `headwind when wind bearing equals firing azimuth`() {
        assertEquals(0.0, WindBearingConverter.toShooterRelative(compassBearing = 0.0, firingAzimuthDeg = 0.0), eps)
        assertEquals(0.0, WindBearingConverter.toShooterRelative(compassBearing = 90.0, firingAzimuthDeg = 90.0), eps)
        assertEquals(0.0, WindBearingConverter.toShooterRelative(compassBearing = 270.0, firingAzimuthDeg = 270.0), eps)
    }

    @Test
    fun `tailwind when wind bearing is opposite firing azimuth`() {
        assertEquals(180.0, WindBearingConverter.toShooterRelative(compassBearing = 180.0, firingAzimuthDeg = 0.0), eps)
        assertEquals(180.0, WindBearingConverter.toShooterRelative(compassBearing = 0.0, firingAzimuthDeg = 180.0), eps)
    }

    @Test
    fun `right-to-left crosswind when wind is 90 degrees right of firing direction`() {
        assertEquals(90.0, WindBearingConverter.toShooterRelative(compassBearing = 90.0, firingAzimuthDeg = 0.0), eps)
        assertEquals(90.0, WindBearingConverter.toShooterRelative(compassBearing = 0.0, firingAzimuthDeg = 270.0), eps)
    }

    @Test
    fun `left-to-right crosswind when wind is 90 degrees left of firing direction`() {
        assertEquals(270.0, WindBearingConverter.toShooterRelative(compassBearing = 270.0, firingAzimuthDeg = 0.0), eps)
        assertEquals(270.0, WindBearingConverter.toShooterRelative(compassBearing = 180.0, firingAzimuthDeg = 270.0), eps)
    }

    @Test
    fun `wraps correctly when bearing minus azimuth is negative`() {
        // bearing=10, azimuth=350 → 10-350 = -340 → should wrap to 20
        assertEquals(20.0, WindBearingConverter.toShooterRelative(compassBearing = 10.0, firingAzimuthDeg = 350.0), eps)
    }

    @Test
    fun `wraps correctly when bearing minus azimuth exceeds 360`() {
        // bearing=350, azimuth=10 → 350-10 = 340
        assertEquals(340.0, WindBearingConverter.toShooterRelative(compassBearing = 350.0, firingAzimuthDeg = 10.0), eps)
    }

    @Test
    fun `result always in 0 to 360 exclusive`() {
        val cases = listOf(0.0 to 0.0, 359.0 to 0.0, 0.0 to 359.0, 180.0 to 180.0)
        for ((bearing, azimuth) in cases) {
            val result = WindBearingConverter.toShooterRelative(bearing, azimuth)
            assert(result >= 0.0 && result < 360.0) {
                "Expected [0,360) but got $result for bearing=$bearing azimuth=$azimuth"
            }
        }
    }
}
