import SwiftUI
import PoseCore

struct PairFeedbackView: View {
    @ObservedObject var model: ReviewerModel
    private func contextBinding<T>(_ path: WritableKeyPath<PairContext, T>, default value: T) -> Binding<T> {
        Binding(get: { model.report?.context[keyPath: path] ?? value }, set: { newValue in
            guard var context = model.report?.context else { return }
            context[keyPath: path] = newValue; model.updateContext(context)
        })
    }
    var body: some View {
        if let report = model.report {
            VStack(alignment: .leading, spacing: 10) {
                if model.leanMode { LeanEvidenceView(model: model); Divider() }
                HStack {
                    Text("Provisional coaching").font(.headline)
                    Spacer()
                    Text(model.hasPreview ? "Awaiting completion of edit" : "Revision \(report.revision) · \(model.isUnsaved ? "Unsaved" : "Saved locally")")
                        .font(.caption).foregroundStyle(model.isUnsaved ? .orange : .secondary)
                }
                Text("For \(RiderLabels.rider) · \(RiderLabels.reference) assumed correct")
                    .font(.subheadline)
                CoachingChecklistView(model: model)
                ForEach(report.coaching) { bullet in
                    if let feature = bullet.feature {
                        Button { model.highlight(feature) } label: { coachingContent(bullet) }.buttonStyle(.plain)
                    } else {
                        coachingContent(bullet).textSelection(.enabled)
                    }
                }
                if report.coaching.isEmpty {
                    Text(coachingStatus(report)).font(.callout)
                }
                if report.hasPhotoCoaching {
                    Text("Photo-based coaching draft · whole-body comparison. These notes come from reviewing this pair, not from the skeleton or an angle threshold.").font(.caption).foregroundStyle(.secondary)
                } else {
                    Text("Draft guidance · elbow differences of 10° or more get attention; this is an adjustable heuristic, not a validated target. Knee guidance uses visual placement only.").font(.caption).foregroundStyle(.secondary)
                }
                ForEach(report.focus) { focus in
                    Button { model.highlight(focus.feature) } label: {
                        VStack(alignment: .leading) {
                            Text("\(focus.feature.label): \(focus.observation.delta ?? 0, specifier: "%.0f")° Rider − Reference rider")
                            Text(focus.suggestion); Text(focus.limitation).font(.caption)
                        }
                    }.buttonStyle(.plain)
                }
                DisclosureGroup("Comparison details · \(report.effectiveCornerDirection.rawValue.capitalized) turn") {
                    Text("Rider and Reference rider come from the session’s saved role assignments. Turn direction uses your saved selection, or the photo assessment when available.").font(.caption)
                    Picker("Direction override", selection: contextBinding(\.cornerDirection, default: .unknown)) {
                        Text("Use photo assessment").tag(CornerDirection.unknown)
                        Text("Left").tag(CornerDirection.left)
                        Text("Right").tag(CornerDirection.right)
                    }.frame(maxWidth: 320)
                    if let review = report.context.photoCoaching {
                        Text(review.provenance).font(.caption2).foregroundStyle(.secondary)
                        if !report.hasPhotoCoaching {
                            Text("Photo coaching is withheld because your direction override differs from the reviewed photos.").font(.caption)
                        }
                    }
                }
                if report.effectiveCornerDirection != .unknown && !report.hasPhotoCoaching {
                    DisclosureGroup("Knee placement · visual review") {
                        Text("Compare Rider with Reference rider at a similar cornering moment. Choose a difference only when the thigh, knee and tank are visible in both views and perspective allows comparison. Consider pelvis and foot placement together; otherwise choose Cannot compare.").font(.caption)
                        ForEach([PairFeature.leftKnee, .rightKnee].filter { !report.unobservableKnees.contains($0) }, id: \.self) { feature in
                            Picker("\(feature.role(in: report.effectiveCornerDirection) ?? "") knee", selection: Binding(
                                get: { report.context.kneePlacement?[feature] ?? .unreviewed },
                                set: { value in
                                    var c = report.context
                                    if c.kneePlacement == nil { c.kneePlacement = [:] }
                                    c.kneePlacement?[feature] = value; model.updateContext(c)
                                })) {
                                    ForEach(KneePlacement.allCases, id: \.self) { Text($0.label).tag($0) }
                                }
                        }
                        if !report.unobservableKnees.isEmpty {
                            Text("Knees marked obscured are excluded from coaching.").font(.caption).foregroundStyle(.secondary)
                        }
                    }
                }
                DisclosureGroup("2D included angles · measurements and evidence") {
                    VStack(alignment: .leading, spacing: 10) {
                        ForEach(report.observations) { observation in
                            VStack(alignment: .leading, spacing: 3) {
                                HStack {
                                    Button(observation.feature.label) { model.highlight(observation.feature) }
                                    Spacer()
                                    Text("\(RiderLabels.rider) \(angle(observation.subject.angle)) · \(RiderLabels.reference) \(angle(observation.reference.angle))").monospacedDigit()
                                }
                                if observation.subject.angle != nil && observation.reference.angle != nil {
                                    Picker("Views", selection: Binding(get: { report.context.comparability[observation.feature, default: .unreviewed] }, set: { value in
                                        var c = report.context; c.comparability[observation.feature] = value; model.updateContext(c)
                                    })) {
                                        Text("Unreviewed").tag(ViewComparability.unreviewed)
                                        Text("Comparable").tag(ViewComparability.comparable)
                                        Text("Not comparable").tag(ViewComparability.notComparable)
                                    }.pickerStyle(.segmented)
                                }
                                if let delta = observation.delta { Text("Visible difference: \(delta, specifier: "%+.0f")° Rider − Reference rider; this is not a target or fault.") }
                                else { Text(observation.comparisonUnavailable ?? "Unavailable").foregroundStyle(.secondary) }
                                missing(observation.subject, role: RiderLabels.rider)
                                missing(observation.reference, role: RiderLabels.reference)
                            }.font(.caption)
                        }
                        Text("Evidence \(report.evidenceHash.prefix(12)) · analyzer \(report.analyzerVersion) · rules \(report.catalogVersion)").font(.caption2)
                    }.padding(.top, 6)
                }
                Text(PairReport.limitations).font(.caption).foregroundStyle(.secondary)
            }.frame(maxWidth: .infinity, alignment: .leading)
        }
    }
    private func angle(_ value: Double?) -> String { value.map { String(format: "%.0f°", $0) } ?? "unavailable" }
    private func coachingContent(_ bullet: CoachingBullet) -> some View {
        VStack(alignment: .leading, spacing: 3) {
            Text("• \(bullet.title)").fontWeight(.medium)
            Text(bullet.detail).font(.caption)
        }.frame(maxWidth: .infinity, alignment: .leading)
    }
    private func coachingStatus(_ report: PairReport) -> String {
        if report.effectiveCornerDirection == .unknown { return "This pair has no turn assessment yet. Set a direction under Comparison details, or add a photo review." }
        return "No actionable difference from the available reviews. Elbows need comparable, reviewed angles; add a knee placement review below for knee guidance."
    }
    @ViewBuilder private func missing(_ measurement: PairMeasurement, role: String) -> some View {
        if !measurement.missingJoints.isEmpty {
            Text("\(role) needs visible review: \(measurement.missingJoints.joined(separator: ", ").replacingOccurrences(of: "_", with: " "))").foregroundStyle(.secondary)
        } else if measurement.unavailable == .invalidGeometry { Text("\(role): degenerate geometry; angle unavailable.") }
    }
}
