import XCTest
@testable import RideFormCore

final class CSVExportTests: XCTestCase {
    func testFullDiskExportFixture() throws {
        let root = URL(fileURLWithPath: "/tmp", isDirectory: true).appendingPathComponent("rideform-u4-export-" + UUID().uuidString)
        let id = UUID(uuidString: "11111111-1111-4111-8111-111111111111")!
        let bundle = root.appendingPathComponent(id.uuidString + ".rideform")
        var manifest = SessionManifest(id: id)
        manifest.boundaries.ended = ClockAnchor(hostUptime: 45.987654321098765, reason: "fixture stopped")
        manifest.boundaries.status = "completed"
        let sample = MotionSample(sequence: 0, sensorTimestamp: 12.123456789012345, receiptUptime: 12.124567890123456, attitudeRadians: Vector3(x: -0.12345678901234568, y: 0.2, z: 0.3), attitudeQuaternion: Quaternion(x: 0.1, y: 0.2, z: 0.3, w: 0.9273618495495703), attitudeRotationMatrix: RotationMatrix(m11: 0.1,m12: 0.2,m13: 0.3,m21: 0.4,m22: 0.5,m23: 0.6,m31: 0.7,m32: 0.8,m33: 0.9), rotationRate: Vector3(x: -1.23,y: 4.56,z: 7.89), gravity: Vector3(x: 0.11,y: -0.22,z: -0.97), userAcceleration: Vector3(x: 0.12,y: 0.13,z: 0.14), magneticField: .invalid(value: Vector3(x: 13.123456789012345,y: -24.5,z: 38.7), reason: "uncalibrated, raw", rawValidityCode: -1), headingRadians: .invalid(value: -1.0, reason: "arbitrary frame", rawValidityCode: 2), headingAccuracyRadians: .unavailable(reason: "SDK unavailable", rawValidityCode: -2))
        var second = sample; second.sequence = 1; second.sensorTimestamp = 42.987654321098765; second.receiptUptime = 42.98876543210987
        second.magneticField = .available(value: Vector3(x: 1,y: 2,z: 3), rawValidityCode: 3)
        second.headingRadians = .available(value: 0.32109876543210987)
        second.headingAccuracyRadians = .invalid(value: nil, reason: "negative", rawValidityCode: -1)
        let calibration = Calibration(id: UUID(uuidString: "22222222-2222-4222-8222-222222222222")!, neutralSamples: [sample], leftGestureSamples: [second], forwardGestureSamples: [sample,second], configuration: CalibrationConfiguration(parameters: ["dispersion": 0.12345678901234568], mountDescription: "sternum, rigid"), actualDurationSeconds: 2.567890123456789, dispersionRadians: 0.0012345678901234567, verified: true)
        let writer = try SessionWriter(directory: bundle, manifest: manifest, calibration: calibration, batchSize: 1000)
        writer.enqueue(sample); writer.enqueue(second)
        writer.enqueue(RawAccelerometerSample(sensorTimestamp: 12.345678901234567, receiptUptime: 12.346789012345678, acceleration: Vector3(x: -0.9876543210987654,y: 0.2,z: -1)))
        writer.enqueue(RawGyroscopeSample(sensorTimestamp: 12.456789012345678, receiptUptime: 12.457890123456789, rotationRate: Vector3(x: 0.12345678901234568,y: 2,z: 3)))
        writer.enqueue(EventMarker(id: UUID(uuidString: "33333333-3333-4333-8333-333333333333")!, sequence: 0, kind: "cue", label: "LEFT", hostUptime: 14.123456789012345, scheduledUptime: 14.12, audioDispatchUptime: 14.124, note: "quoted \"note\", line\nbreak"))
        let done = expectation(description: "saved")
        writer.finalize(manifest: manifest) { result in if case .failure(let error) = result { XCTFail(String(describing: error)) }; done.fulfill() }
        wait(for: [done], timeout: 5)
        let loaded = try SessionIO.load(bundle)
        XCTAssertEqual(loaded.motion.samples, [sample,second]); XCTAssertEqual(loaded.calibration, calibration)
        let csv = try CSVExport.write(loaded, to: root.appendingPathComponent("CSV"))
        XCTAssertEqual(csv.filter { $0.pathExtension == "csv" }.count, 8)
        let archive = root.appendingPathComponent("master.zip")
        try MasterArchive.write(bundle: bundle, to: archive)
        XCTAssertThrowsError(try MasterArchive.write(bundle: bundle, to: archive))
        let text = try String(contentsOf: root.appendingPathComponent("CSV/motion.csv"))
        XCTAssertTrue(text.contains(String(sample.sensorTimestamp)))
        XCTAssertTrue(text.contains("magnetic_field_raw_validity_code"))
        print("U4_EXPORT_ARTIFACT=\(root.path)")
    }
}
