import XCTest
@testable import PoseCore

func reviewedPair() throws -> ReviewDocument {
    var doc = pairDocument()
    for i in doc.frames.indices {
        for feature in PairFeature.allCases {
            let points = [Point2(x: 100, y: 200), Point2(x: 200, y: 200), Point2(x: 200, y: 300)]
            for (joint, point) in zip(feature.joints, points) { try doc.frames[i].setJoint(joint, point: point, state: .confirmed) }
        }
    }
    let pair = try XCTUnwrap(PairReview.resolve(doc.frames).first)
    var c = try PairContext(document: doc, pair: pair)
    c.subjectConfirmed = true; c.referenceConfirmed = true
    for feature in PairFeature.allCases { c.comparability[feature] = .comparable }
    doc.comparisonContexts = [c]
    return doc
}
final class PairAnalysisTests: XCTestCase {
    func testKnownAnglesAndInvalidGeometry() throws {
        let p = Point2(x: 0, y: 0), a = Point2(x: 1, y: 0)
        XCTAssertEqual(try XCTUnwrap(PairAnalysis.includedAngle(a, p, a)), 0, accuracy: 1e-8)
        XCTAssertEqual(try XCTUnwrap(PairAnalysis.includedAngle(a, p, Point2(x: 0, y: 1))), 90, accuracy: 1e-8)
        XCTAssertEqual(try XCTUnwrap(PairAnalysis.includedAngle(a, p, Point2(x: -1, y: 0))), 180, accuracy: 1e-8)
        XCTAssertNil(PairAnalysis.includedAngle(p, p, a))
        XCTAssertNil(PairAnalysis.includedAngle(Point2(x: .nan, y: 0), p, a))
        for size in [0.001, 1, 1000000] {
            XCTAssertEqual(try XCTUnwrap(PairAnalysis.includedAngle(Point2(x: 10, y: 20 + size), Point2(x: 10, y: 20), Point2(x: 10 - size, y: 20))), 90, accuracy: 1e-7)
        }
    }
    func testReviewedOnlyAndContextGates() throws {
        var doc = try reviewedPair()
        let pair = try XCTUnwrap(PairReview.resolve(doc.frames).first)
        let report = try PairAnalysis.analyze(doc, pair: pair)
        XCTAssertEqual(report.observations.filter { $0.delta != nil }.count, 4)
        try doc.frames[0].setJoint("left_knee", point: nil, state: .occluded)
        let withdrawn = try PairAnalysis.analyze(doc, pair: pair)
        XCTAssertNil(withdrawn.observations.first { $0.feature == .leftKnee }?.delta)
        XCTAssertNotNil(withdrawn.observations.first { $0.feature == .rightKnee }?.delta)
        doc.comparisonContexts[0].subjectConfirmed = false
        XCTAssertNotNil(try PairAnalysis.analyze(doc, pair: pair).observations.first { $0.feature == .leftElbow }?.delta)
        XCTAssertTrue(try PairAnalysis.analyze(pairDocument(), pair: pair).observations.allSatisfy { $0.subject.angle == nil && $0.reference.angle == nil })
    }
}
