import SwiftUI
import SwiftData

/// 时间线条目反查到的源记录,驱动只读详情 sheet。
/// 注:报告详情这里是 W2 轻量只读版;W4 的 C2 `ReportDetailView`(三 Tab + 对比上次)另建,
/// 届时把时间线报告行改路由到 C2 即可,本类型不与之冲突。
enum TimelineDetail {
    case indicator(Indicator)
    case bloodPressure(sys: Indicator, dia: Indicator?)
    case report(Report)
    case diary(DiaryEntry)
    case symptom(Symptom)

    /// 把时间线条目反查回源记录(id 形如 `<kind>-<persistentModelID>` / `bp-<sysID>-<diaID>`)。
    /// 主页「最近记录」与档案库 C1 共用同一套反查,避免逻辑重复。无法定位源记录时返回 nil。
    static func resolve(for entry: TimelineEntry,
                        indicators: [Indicator],
                        reports: [Report],
                        diaries: [DiaryEntry],
                        symptoms: [Symptom]) -> TimelineDetail? {
        switch entry.kind {
        case .report:
            return reports.first { "report-\($0.persistentModelID)" == entry.id }
                .map(TimelineDetail.report)
        case .diary:
            return diaries.first { "diary-\($0.persistentModelID)" == entry.id }
                .map(TimelineDetail.diary)
        case .symptom:
            return symptoms.first { "symptom-\($0.persistentModelID)" == entry.id }
                .map(TimelineDetail.symptom)
        case .indicator:
            if let i = indicators.first(where: { "indicator-\($0.persistentModelID)" == entry.id }) {
                return .indicator(i)
            }
            // 合并血压条目:bp-<sysID>-<diaID>
            if entry.id.hasPrefix("bp-"),
               let sys = indicators.first(where: { entry.id.hasPrefix("bp-\($0.persistentModelID)-") }) {
                // 用 id 里编码的 diaID 精确反查,不再用 ±5s 时间窗近似匹配
                //(后者在同日多次量血压时会把详情配到错误的舒张读数)。
                let dia = indicators.first { entry.id.hasSuffix("-\($0.persistentModelID)") }
                return .bloodPressure(sys: sys, dia: dia)
            }
            return nil
        }
    }
}

/// 时间线条目的只读详情:展示该记录的完整字段。各类型一屏看完,不可编辑。
struct TimelineEntryDetailView: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.modelContext) private var ctx
    let detail: TimelineDetail

    @State private var showDeleteConfirm = false

    var body: some View {
        VStack(spacing: 0) {
            header
            ScrollView {
                VStack(alignment: .leading, spacing: 16) {
                    bodyContent
                    deleteButton
                }
                .padding(.horizontal, 20)
                .padding(.vertical, 16)
                .frame(maxWidth: .infinity, alignment: .leading)
            }
        }
        .background(Tj.Palette.sand.ignoresSafeArea())
        .presentationDetents([.medium, .large])
        .presentationDragIndicator(.visible)
        .presentationBackground(Tj.Palette.sand)
        .presentationCornerRadius(Tj.Radius.xl)
        .alert(String(appLoc: "永久删除这条记录?"), isPresented: $showDeleteConfirm) {
            Button(String(appLoc: "删除"), role: .destructive) { performDelete() }
            Button(String(appLoc: "取消"), role: .cancel) { }
        } message: {
            Text("删除后无法恢复。")
        }
    }

    // MARK: - 删除(永久:SwiftData 硬删 + Vault 原图 unlink,见 CLAUDE.md §6)

    private var deleteButton: some View {
        Button(role: .destructive) { showDeleteConfirm = true } label: {
            Label(String(appLoc: "永久删除"), systemImage: "trash")
                .font(.system(size: 12, weight: .medium))
                .foregroundStyle(Tj.Palette.brick.opacity(0.8))
                .padding(.horizontal, 14)
                .padding(.vertical, 8)
                .background(
                    RoundedRectangle(cornerRadius: Tj.Radius.md, style: .continuous)
                        .strokeBorder(Tj.Palette.brick.opacity(0.3), lineWidth: 1)
                )
                // 纯描边按钮:补 contentShape 让整框可点(否则中间透明区点不到)。
                .contentShape(Rectangle())
        }
        .buttonStyle(.plain)
        .padding(.top, 8)
    }

    private func performDelete() {
        switch detail {
        case .indicator(let i):
            deleteIndicator(i)
        case .bloodPressure(let sys, let dia):
            deleteIndicator(sys)
            if let dia { deleteIndicator(dia) }
        case .report(let r):
            // cascade 只删 Asset/Indicator 记录,Vault 里的 JPEG 要手动 unlink。
            var paths = Set(r.assets.map(\.relativePath))
            paths.formUnion(r.indicators.compactMap { $0.asset?.relativePath })
            for p in paths { try? FileVault.shared.remove(relativePath: p) }
            ctx.delete(r)
        case .diary(let d):
            ctx.delete(d)
        case .symptom(let s):
            ctx.delete(s)
        }
        try? ctx.save()
        dismiss()
    }

    /// 删一条指标:先 unlink 其原图文件 + Asset 记录(关系默认 nullify,不会自动级联),再删指标本身。
    private func deleteIndicator(_ i: Indicator) {
        if let asset = i.asset {
            try? FileVault.shared.remove(relativePath: asset.relativePath)
            ctx.delete(asset)
        }
        ctx.delete(i)
    }

    // MARK: - Header

    private var header: some View {
        HStack(spacing: 12) {
            Button { dismiss() } label: {
                Image(systemName: "xmark")
                    .font(.system(size: 16, weight: .semibold))
                    .foregroundStyle(Tj.Palette.text)
                    .frame(width: 32, height: 32)
                    .background(Circle().fill(Tj.Palette.sand2))
            }
            Text(titleText)
                .font(.tjH2())
                .foregroundStyle(Tj.Palette.text)
            Spacer()
            TjLockChip()
        }
        .padding(.horizontal, 20)
        .padding(.vertical, 14)
        .background(Tj.Palette.sand)
        .overlay(alignment: .bottom) {
            Rectangle().fill(Tj.Palette.lineSoft).frame(height: 1)
        }
    }

    private var titleText: String {
        switch detail {
        case .indicator:     return String(appLoc: "指标详情")
        case .bloodPressure: return String(appLoc: "血压详情")
        case .report:        return String(appLoc: "报告详情")
        case .diary:         return String(appLoc: "日记详情")
        case .symptom:       return String(appLoc: "症状详情")
        }
    }

    @ViewBuilder
    private var bodyContent: some View {
        switch detail {
        case .indicator(let i):              indicatorBody(i)
        case .bloodPressure(let s, let d):   bpBody(sys: s, dia: d)
        case .report(let r):                 reportBody(r)
        case .diary(let d):                  diaryBody(d)
        case .symptom(let s):                symptomBody(s)
        }
    }

    // MARK: - 指标

    private func indicatorBody(_ i: Indicator) -> some View {
        card {
            HStack(alignment: .firstTextBaseline) {
                Text(i.name).font(.tjH2()).foregroundStyle(Tj.Palette.text)
                Spacer()
                statusChip(i.status)
            }
            HStack(alignment: .firstTextBaseline, spacing: 4) {
                Text(i.value)
                    .font(.system(size: 30, weight: .bold, design: .rounded))
                    .foregroundStyle(i.status == .normal ? Tj.Palette.text : Tj.Palette.brick)
                if !i.unit.isEmpty {
                    Text(i.unit).font(.system(size: 14)).foregroundStyle(Tj.Palette.text3)
                }
            }
            divider
            if !i.range.isEmpty { field(String(appLoc: "参考范围"), i.range) }
            field(String(appLoc: "记录时间"), Self.dateTimeText(i.capturedAt))
            field(String(appLoc: "来源"), i.report?.title ?? String(appLoc: "异常项快拍"))
            if let note = i.note, !note.isEmpty { field(String(appLoc: "备注"), note) }
        }
    }

    // MARK: - 血压(合并条目)

    private func bpBody(sys: Indicator, dia: Indicator?) -> some View {
        let combined: IndicatorStatus = sys.status != .normal
            ? sys.status
            : (dia?.status ?? .normal)
        return card {
            HStack(alignment: .firstTextBaseline) {
                Text(String(appLoc: "血压")).font(.tjH2()).foregroundStyle(Tj.Palette.text)
                Spacer()
                statusChip(combined)
            }
            HStack(alignment: .firstTextBaseline, spacing: 4) {
                Text("\(sys.value)/\(dia?.value ?? "—")")
                    .font(.system(size: 30, weight: .bold, design: .rounded))
                    .foregroundStyle(combined == .normal ? Tj.Palette.text : Tj.Palette.brick)
                Text("mmHg").font(.system(size: 14)).foregroundStyle(Tj.Palette.text3)
            }
            divider
            if !sys.range.isEmpty { field(String(appLoc: "参考范围"), sys.range) }
            field(String(appLoc: "记录时间"), Self.dateTimeText(sys.capturedAt))
        }
    }

    // MARK: - 报告

    private func reportBody(_ r: Report) -> some View {
        let sorted = r.indicators.sorted {
            ($0.status == .normal ? 1 : 0) < ($1.status == .normal ? 1 : 0)
        }
        return VStack(alignment: .leading, spacing: 16) {
            card {
                Text(r.title).font(.tjH2()).foregroundStyle(Tj.Palette.text)
                HStack(spacing: 8) {
                    TjBadge(text: r.type.label, style: .neutral)
                    Text(Self.dateText(r.reportDate))
                        .font(.system(size: 12)).foregroundStyle(Tj.Palette.text3)
                    if !r.assets.isEmpty {
                        Text(String(appLoc: "原图\(r.assets.count)张"))
                            .font(.system(size: 12)).foregroundStyle(Tj.Palette.text3)
                    }
                }
                if let inst = r.institution, !inst.isEmpty {
                    field(String(appLoc: "机构"), inst)
                }
            }

            if let sum = r.summary, !sum.isEmpty {
                card {
                    Text(String(appLoc: "摘要"))
                        .font(.system(size: 12, weight: .semibold)).foregroundStyle(Tj.Palette.text2)
                    Text(sum).font(.system(size: 14)).foregroundStyle(Tj.Palette.text)
                        .fixedSize(horizontal: false, vertical: true)
                }
            }

            if !r.indicators.isEmpty {
                card {
                    Text(String(appLoc: "指标"))
                        .font(.system(size: 12, weight: .semibold)).foregroundStyle(Tj.Palette.text2)
                    ForEach(sorted) { ind in
                        HStack {
                            Text(ind.name).font(.system(size: 14)).foregroundStyle(Tj.Palette.text)
                            Spacer(minLength: 8)
                            Text(ind.unit.isEmpty ? ind.value : "\(ind.value) \(ind.unit)")
                                .font(.system(size: 13, design: .monospaced))
                                .foregroundStyle(ind.status == .normal ? Tj.Palette.text2 : Tj.Palette.brick)
                            statusChip(ind.status)
                        }
                    }
                }
            }

            if let note = r.note, !note.isEmpty {
                card { field(String(appLoc: "备注"), note) }
            }
        }
    }

    // MARK: - 日记

    private func diaryBody(_ d: DiaryEntry) -> some View {
        VStack(alignment: .leading, spacing: 16) {
            card {
                Text(Self.dateTimeText(d.createdAt))
                    .font(.system(size: 12)).foregroundStyle(Tj.Palette.text3)
                Text(d.content)
                    .font(.system(size: 15))
                    .foregroundStyle(Tj.Palette.text)
                    .textSelection(.enabled)
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .fixedSize(horizontal: false, vertical: true)
                if !d.tags.isEmpty {
                    field(String(appLoc: "标签"), d.tags.map { "#\($0)" }.joined(separator: "  "))
                }
            }
        }
    }

    // MARK: - 症状

    private func symptomBody(_ s: Symptom) -> some View {
        card {
            HStack(alignment: .firstTextBaseline) {
                Text(s.name).font(.tjH2()).foregroundStyle(Tj.Palette.text)
                Spacer()
                if s.isOngoing {
                    Text(String(appLoc: "进行中"))
                        .font(.system(size: 12, weight: .semibold))
                        .foregroundStyle(Tj.Palette.brick)
                        .padding(.horizontal, 8).padding(.vertical, 4)
                        .background(Capsule().fill(Tj.Palette.brick.opacity(0.14)))
                }
            }
            divider
            field(String(appLoc: "程度"), "\(s.severity) / 5")
            field(String(appLoc: "开始"), Self.dateTimeText(s.startedAt))
            field(String(appLoc: "结束"), s.endedAt.map(Self.dateTimeText) ?? String(appLoc: "进行中"))
            field(String(appLoc: "持续"), formatDuration(s.duration))
            if let note = s.note, !note.isEmpty { field(String(appLoc: "备注"), note) }
            if !s.tags.isEmpty {
                field(String(appLoc: "标签"), s.tags.map { "#\($0)" }.joined(separator: "  "))
            }
        }
    }

    // MARK: - 复用件

    @ViewBuilder
    private func card<Content: View>(@ViewBuilder content: () -> Content) -> some View {
        VStack(alignment: .leading, spacing: 10) { content() }
            .padding(14)
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(
                RoundedRectangle(cornerRadius: Tj.Radius.md, style: .continuous)
                    .fill(Tj.Palette.paper)
            )
            .overlay(
                RoundedRectangle(cornerRadius: Tj.Radius.md, style: .continuous)
                    .strokeBorder(Tj.Palette.lineSoft, lineWidth: 1)
            )
    }

    private func field(_ label: String, _ value: String) -> some View {
        HStack(alignment: .top, spacing: 12) {
            Text(label).font(.system(size: 13)).foregroundStyle(Tj.Palette.text3)
            Spacer(minLength: 12)
            Text(value)
                .font(.system(size: 14, weight: .medium))
                .foregroundStyle(Tj.Palette.text)
                .multilineTextAlignment(.trailing)
                .fixedSize(horizontal: false, vertical: true)
        }
    }

    private var divider: some View {
        Rectangle().fill(Tj.Palette.lineSoft).frame(height: 1)
    }

    private func statusChip(_ s: IndicatorStatus) -> some View {
        let text: String
        let color: Color
        let arrow: String
        switch s {
        case .high:   text = String(appLoc: "偏高"); color = Tj.Palette.brick; arrow = "↑"
        case .low:    text = String(appLoc: "偏低"); color = Tj.Palette.brick; arrow = "↓"
        case .normal: text = String(appLoc: "正常"); color = Tj.Palette.leaf;  arrow = ""
        }
        return HStack(spacing: 3) {
            if !arrow.isEmpty { Text(arrow).font(.system(size: 11, weight: .bold)) }
            Text(text).font(.system(size: 12, weight: .semibold))
        }
        .foregroundStyle(color)
        .padding(.horizontal, 8)
        .padding(.vertical, 4)
        .background(Capsule().fill(color.opacity(0.14)))
    }

    private nonisolated static func dateTimeText(_ d: Date) -> String {
        d.formatted(.dateTime.year().month().day().hour().minute())
    }

    private nonisolated static func dateText(_ d: Date) -> String {
        d.formatted(.dateTime.year().month().day())
    }
}
