import Foundation
import Darwin
import RideFormCore

/// CMLogItem.h defines timestamp as Mach absolute time, expressed in seconds.
/// This clock excludes sleep; mach_continuous_time is deliberately not used.
final class SessionClock {
    private let scale: Double
    private let lock = NSLock()
    var mapping: ClockMapping { lock.lock(); defer { lock.unlock() }; return mappingStorage }
    private var mappingStorage = ClockMapping(sensorClock: "CoreMotion.CMLogItem.timestamp (Mach absolute seconds)", hostClock: "mach_absolute_time scaled with mach_timebase_info", units: "seconds", sensorToHostOffset: 0, validated: false, checks: ["SDK CMLogItem.h: Mach absolute time at which item is valid"])
    private var previous: (sensor: Double, receipt: Double)?
    private var checks = 0
    private var failed = false

    init() {
        var info = mach_timebase_info_data_t()
        mach_timebase_info(&info)
        scale = Double(info.numer) / Double(info.denom) / 1_000_000_000
    }
    func resetValidation() {
        lock.lock(); defer { lock.unlock() }
        previous = nil; checks = 0; failed = false
        mappingStorage.validated = false
        mappingStorage.checks = ["CMLogItem.h and host use Mach absolute seconds; offset 0; observation pending"]
    }
    func now() -> Double { Double(mach_absolute_time()) * scale }
    func anchor(reason: String) -> ClockAnchor { ClockAnchor(wallClock: Date(), hostUptime: now(), reason: reason) }
    /// Validate sign, matching progression and bounded callback age. No fitted offset hides delay.
    /// Call for one ordered stream (fused, or gyro in raw-only diagnostics).
    func validateMapping(sensorTimestamp: Double, receiptUptime: Double) {
        lock.lock(); defer { lock.unlock() }
        let age = receiptUptime - sensorTimestamp
        var valid = sensorTimestamp.isFinite && receiptUptime.isFinite && age >= 0 && age < 5
        if let last = previous {
            let sensorDelta = sensorTimestamp - last.sensor
            let hostDelta = receiptUptime - last.receipt
            valid = valid && sensorDelta > 0 && hostDelta >= 0 && abs(hostDelta - sensorDelta) < 1
        }
        checks += 1
        failed = failed || !valid
        previous = (sensorTimestamp, receiptUptime)
        mappingStorage.validated = checks >= 10 && !failed
        mappingStorage.checks = ["CMLogItem.h and host use Mach absolute seconds; offset 0", "\(checks) observed checks; age [0,5)s, positive sensor progression, host/sensor delta discrepancy <1s", "failed=\(failed); physical sensor latency unmeasured"]
    }
}
