import XCTest
import RideFormCore
@testable import RideForm

@MainActor
final class DiagnosticsCaptureTests: XCTestCase {
    func testAllDiagnosticModesCaptureWithoutCalibrationAndPersistEarlyStop() async throws {
        #if targetEnvironment(simulator)
        for mode in CaptureMode.allCases {
            let directory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
            let controller = RecordingController(repository:SessionRepository(directory:directory),synthetic:true)
            controller.startDiagnostics(mode:mode); controller.startDiagnostics(mode:mode)
            try await eventually { controller.state == .recording && controller.counts[mode == .rawOnly ? .gyroscope : .motion,default:0] >= 20 }
            XCTAssertNil(controller.angles)
            controller.stopRecording(); controller.stopRecording()
            try await eventually { controller.state == .saved }
            let session = try SessionIO.load(XCTUnwrap(controller.savedURL))
            XCTAssertNil(session.calibration)
            XCTAssertEqual(session.events.map(\.label),["STATIONARY","END"])
            XCTAssertEqual(session.events.map(\.sequence),[0,1])
            XCTAssertTrue(session.manifest.clockMapping.validated)
            if mode == .rawOnly { XCTAssertTrue(session.motion.samples.isEmpty); XCTAssertFalse(session.gyroscope.samples.isEmpty); XCTAssertFalse(session.accelerometer.samples.isEmpty) }
            if mode == .fusedOnly { XCTAssertFalse(session.motion.samples.isEmpty); XCTAssertTrue(session.gyroscope.samples.isEmpty); XCTAssertTrue(session.accelerometer.samples.isEmpty) }
            if mode == .combined { XCTAssertFalse(session.motion.samples.isEmpty); XCTAssertFalse(session.gyroscope.samples.isEmpty); XCTAssertFalse(session.accelerometer.samples.isEmpty) }
            let report = try SensorDiagnostics.analyze(session:session)
            XCTAssertTrue(report.qualityFlags.contains("stationary_phase_shorter_than_30_seconds"))
            XCTAssertTrue(report.qualityFlags.contains("rider_orientation_unavailable_until_calibrated"))
            controller.acknowledgeSaved()
            if mode == .rawOnly {
                controller.beginCalibration()
                XCTAssertEqual(controller.state,.uncalibrated)
                XCTAssertTrue(controller.status.contains("Raw-only"))
            }
        }
        #endif
    }
    private func eventually(_ predicate: () -> Bool) async throws {
        for _ in 0..<120 { if predicate() { return }; try await Task.sleep(for:.milliseconds(50)) }
        XCTFail("Diagnostic capture timed out")
        throw NSError(domain:"Diagnostic timeout",code:1)
    }
}
