import Testing
import Foundation
@testable import AudioCore

@Suite struct CalibratorTests {
    let sr = 48000.0

    @Test func recoversKnownDelay() {
        let (signal, positions) = Calibrator.calibrationSignal(sampleRate: sr)

        // Simulate the acoustic loopback: 137 ms delay, attenuation, noise.
        let delaySamples = Int(0.137 * sr)
        var recorded = [Float](repeating: 0, count: signal.count + delaySamples + 4800)
        var rng = SystemRandomNumberGenerator()
        for i in 0..<recorded.count {
            recorded[i] = Float.random(in: -0.01...0.01, using: &rng)
        }
        for (i, s) in signal.enumerated() {
            recorded[i + delaySamples] += s * 0.3
        }

        let measured = Calibrator.measureLatency(
            recorded: recorded, clickPositions: positions, sampleRate: sr
        )
        #expect(measured != nil)
        if let measured {
            #expect(abs(measured - 0.137) < 0.001, "measured \(measured)")
        }
    }

    @Test func refusesPureNoise() {
        let (_, positions) = Calibrator.calibrationSignal(sampleRate: sr)
        var rng = SystemRandomNumberGenerator()
        let noise = (0..<Int(3 * sr)).map { _ in Float.random(in: -0.05...0.05, using: &rng) }
        let measured = Calibrator.measureLatency(
            recorded: noise, clickPositions: positions, sampleRate: sr
        )
        #expect(measured == nil)
    }

    @Test func toleratesOneEcho() {
        let (signal, positions) = Calibrator.calibrationSignal(sampleRate: sr)
        let delaySamples = Int(0.080 * sr)
        var recorded = [Float](repeating: 0, count: signal.count + delaySamples + 9600)
        for (i, s) in signal.enumerated() {
            recorded[i + delaySamples] += s * 0.4
            // Strong echo 55 ms later.
            let echoAt = i + delaySamples + Int(0.055 * sr)
            if echoAt < recorded.count { recorded[echoAt] += s * 0.35 }
        }
        let measured = Calibrator.measureLatency(
            recorded: recorded, clickPositions: positions, sampleRate: sr
        )
        #expect(measured != nil)
        if let measured {
            #expect(abs(measured - 0.080) < 0.001, "measured \(measured)")
        }
    }
}
