package com.onthelevel.core.sensors

import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import kotlin.math.cos
import kotlin.math.sin

class SurfaceCalibrationValidationTest {

    @Test
    fun `accepts a combined bias at or below three degrees`() {
        assertTrue(SurfaceCalibrationValidation.isAcceptable(SurfaceCalibration(3.0, 0.0)))
        assertTrue(SurfaceCalibrationValidation.isAcceptable(SurfaceCalibration(1.8, 2.4)))
    }

    @Test
    fun `rejects a combined bias above three degrees`() {
        assertFalse(SurfaceCalibrationValidation.isAcceptable(SurfaceCalibration(3.01, 0.0)))
        assertFalse(SurfaceCalibrationValidation.isAcceptable(SurfaceCalibration(2.5, 2.5)))
    }

    // A 5° surface is the worst permitted case (bias magnitude ≤ 5° is allowed to reach
    // the mean). biasPitch/Roll are the fixed device bias; the true tilt rotates with
    // the phone about the surface normal.
    private val biasPitch = 0.3
    private val biasRoll = -0.2
    private val tilt = 5.0

    private fun sampleAt(rotationDegrees: Double) = CapturedSurfaceSample(
        pitchDegrees = biasPitch + tilt * cos(Math.toRadians(rotationDegrees)),
        rollDegrees = biasRoll + tilt * sin(Math.toRadians(rotationDegrees)),
    )

    @Test
    fun `clean four-point turn is consistent`() {
        val clean = listOf(sampleAt(0.0), sampleAt(90.0), sampleAt(180.0), sampleAt(270.0))
        assertTrue(SurfaceCalibrationValidation.isRotationConsistent(clean))
    }

    @Test
    fun `sloppy four-point turn is rejected`() {
        // Second position over-rotated 10° (100° instead of 90°). The (90,270) pair no
        // longer cancels, so the two independent bias estimates diverge past tolerance —
        // a malformed rotation the 3° magnitude guard alone cannot catch.
        val sloppy = listOf(sampleAt(0.0), sampleAt(100.0), sampleAt(180.0), sampleAt(270.0))
        assertFalse(SurfaceCalibrationValidation.isRotationConsistent(sloppy))
    }

    @Test
    fun `two-point set has no cross-check and is always consistent`() {
        val twoPoint = listOf(CapturedSurfaceSample(0.8, -0.1), CapturedSurfaceSample(-0.2, 0.5))
        assertTrue(SurfaceCalibrationValidation.isRotationConsistent(twoPoint))
    }
}
