import Foundation
import XCTest
@testable import RideFormCore

final class WatchPortabilityTests: XCTestCase {
    func testSavedWatchFormatUsesIdenticalPortablePipeline() throws {
        let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
        defer { try? FileManager.default.removeItem(at: root) }
        let samples = (0...300).map { index in
            let t = Double(index) * 0.01
            return MotionSample(sequence: UInt64(index), sensorTimestamp: 50 + t,
                receiptUptime: 50.02 + t,
                attitudeQuaternion: OrientationMath.quaternion(rotationVector: Vector3(x: 0.2 * sin(t))),
                rotationRate: Vector3(x: 0.2 * cos(t)), gravity: Vector3(z: -1))
        }
        let calibration = Calibration(neutralSamples: [samples[0]], actualDurationSeconds: 2.5,
            verified: true, method: "synthetic Watch portability fixture")
        var manifest = SessionManifest(platform: .appleWatch, deviceModel: "synthetic apple_watch; no hardware evidence",
            rotationConvention: RotationConvention(capturedToCanonical: "identity", verified: true), calibrationID: calibration.id,
            analysisConfiguration: MotionAnalyzer.defaultConfiguration)
        let writer = try SessionWriter(directory: root.appendingPathComponent("watch.rideform"), manifest: manifest, calibration: calibration)
        samples.forEach(writer.enqueue)
        let events = [EventMarker(sequence: 0, label: "LEFT", hostUptime: 51)]
        events.forEach(writer.enqueue)
        manifest.boundaries.status = "completed"
        let saved = expectation(description: "persist Watch fixture")
        writer.finalize(manifest: manifest) { result in
            if case .failure(let error) = result { XCTFail("\(error)") }
            saved.fulfill()
        }
        wait(for: [saved], timeout: 5)
        let watch = try SessionIO.load(root.appendingPathComponent("watch.rideform"))
        XCTAssertEqual(watch.manifest.platform, .appleWatch)
        XCTAssertEqual(watch.motion.samples, samples)
        XCTAssertEqual(watch.events, events)
        XCTAssertEqual(watch.calibration, calibration)
        let identity = try DerivedSidecar<AnalysisResult>.identity(watch)
        let analysis = try MotionAnalyzer.analyze(session: watch)
        XCTAssertEqual(analysis.inputSHA256, identity)
        XCTAssertEqual(analysis.rawTrace.count, samples.count)
        let export = root.appendingPathComponent("CSV")
        _ = try CSVExport.write(watch, to: export)
        let independentManifest = try JSONDecoder().decode(SessionManifest.self, from: Data(contentsOf: export.appendingPathComponent("manifest.json")))
        XCTAssertEqual(independentManifest, watch.manifest)
        var phone = watch
        phone.manifest.platform = .iphone
        let phoneAnalysis = try MotionAnalyzer.analyze(session: phone)
        XCTAssertEqual(phoneAnalysis.rawTrace, analysis.rawTrace)
        XCTAssertEqual(phoneAnalysis.configuredTrace, analysis.configuredTrace)
        XCTAssertEqual(phoneAnalysis.transitions, analysis.transitions)
        XCTAssertEqual(phoneAnalysis.configuration, analysis.configuration)
        XCTAssertNotEqual(phoneAnalysis.inputSHA256, analysis.inputSHA256)
        XCTAssertEqual(identity, try DerivedSidecar<AnalysisResult>.identity(SessionIO.load(root.appendingPathComponent("watch.rideform"))))
    }
}
