import Foundation

public enum KneePlacement: String, Codable, CaseIterable, Sendable {
    case unreviewed, closerToTank, fartherFromTank, similar, unassessable
    public var label: String {
        switch self {
        case .unreviewed: "Not reviewed"
        case .closerToTank: "Closer to tank than reference"
        case .fartherFromTank: "Farther from tank than reference"
        case .similar: "Similar to reference"
        case .unassessable: "Cannot compare these views"
        }
    }
}

public struct CoachingBullet: Equatable, Sendable, Identifiable {
    public let feature: PairFeature?
    public let title: String
    public let detail: String
    public var provenance = "user-assumed-reference"
    public var version = "damien-reference-draft-3"
    public var id: String { feature?.rawValue ?? title }
}

extension PairFeature {
    public func role(in direction: CornerDirection) -> String? {
        guard direction != .unknown else { return nil }
        let left = self == .leftElbow || self == .leftKnee
        return left == (direction == .left) ? "Inside" : "Outside"
    }
    public var isElbow: Bool { self == .leftElbow || self == .rightElbow }
}

extension PairReport {
    public var effectiveCornerDirection: CornerDirection {
        context.cornerDirection == .unknown ? (context.photoCoaching?.cornerDirection ?? .unknown) : context.cornerDirection
    }
    public var hasPhotoCoaching: Bool {
        context.photoCoaching?.cornerDirection == effectiveCornerDirection && context.photoCoaching != nil
    }
    /// Separate from coach-reviewed rules: the reference is assumed correct by the user.
    public var coaching: [CoachingBullet] {
        if let review = context.photoCoaching, hasPhotoCoaching {
            return review.points.map { CoachingBullet(feature: nil, title: $0.title, detail: $0.detail,
                provenance: review.provenance, version: "photo-review-1") }
        }
        guard effectiveCornerDirection != .unknown else { return [] }
        let ordered = observations.sorted {
            let a = ($0.feature.isElbow ? 0 : 2) + ($0.feature.role(in: effectiveCornerDirection) == "Inside" ? 0 : 1)
            let b = ($1.feature.isElbow ? 0 : 2) + ($1.feature.role(in: effectiveCornerDirection) == "Inside" ? 0 : 1)
            return a < b
        }
        return Array(ordered.compactMap { observation -> CoachingBullet? in
            let feature = observation.feature
            guard let role = feature.role(in: effectiveCornerDirection) else { return nil }
            if feature.isElbow {
                guard let delta = observation.delta, abs(delta) >= 10 else { return nil }
                let bend = delta > 0 ? "more" : "less"
                return CoachingBullet(feature: feature, title: "\(role) elbow: explore \(bend) bend",
                    detail: "Your elbow appears \(String(format: "%.0f", abs(delta)))° \(delta > 0 ? "straighter" : "more bent") than the reference. Compare the whole arm shape while keeping relaxed access to the controls. Perspective may explain part of the difference.")
            }
            guard !unobservableKnees.contains(feature), let placement = context.kneePlacement?[feature] else { return nil }
            let action: String
            switch placement {
            case .closerToTank: action = role == "Inside" ? "open toward the turn" : "compare a less tucked position"
            case .fartherFromTank: action = "hold closer to the tank"
            default: return nil
            }
            return CoachingBullet(feature: feature, title: "\(role) knee: \(action)",
                detail: "Your visual review places this knee \(placement == .closerToTank ? "closer to" : "farther from") the tank than the reference. Compare how the thigh opens at the hip, together with pelvis and foot placement. This does not measure hip rotation, foot contact or tank pressure.")
        }.prefix(3))
    }
}
