import SwiftUI
import SwiftData
import UIKit

enum TjTab: String, Hashable, CaseIterable {
    case home, records, trend, me
    var label: String {
        switch self {
        case .home:    return String(appLoc: "主页")
        case .records: return String(appLoc: "记录")
        case .trend:   return String(appLoc: "趋势")
        case .me:      return String(appLoc: "我的")
        }
    }
    var icon: String {
        switch self {
        case .home:    return "house"
        case .records: return "list.bullet.rectangle"
        case .trend:   return "chart.line.uptrend.xyaxis"
        case .me:      return "person.circle"
        }
    }
    /// 屏上从左到右的位置,用于决定页面 push 过渡的方向。
    var index: Int {
        switch self {
        case .home:    return 0
        case .records: return 1
        case .trend:   return 2
        case .me:      return 3
        }
    }
}

enum ActiveFlow: Identifiable {
    case quick, archive
    var id: String { String(describing: self) }
}

struct RootView: View {
    @Environment(\.modelContext) private var ctx
    @Environment(\.scenePhase) private var scenePhase
    @State private var tab: TjTab = .home
    /// 页面 push 过渡的来向:切到右侧 tab 时从 trailing 推入,切到左侧时从 leading 推入。
    @State private var pushEdge: Edge = .trailing
    /// 切到记录页时预选的分类 chip。首页「我的报告档案」进入时设 `.report`,普通点 tab 清空。
    @State private var pendingRecordsFilter: TimelineKind?
    @State private var showRecordSheet = false
    @State private var activeFlow: ActiveFlow?
    @State private var showSymptomStart = false
    @State private var showDiary = false
    /// 语音「写日记」直达:跳过日记 sheet 顶部入口选择,光标直接落到正文。
    @State private var diaryDirectWrite = false
    @State private var showIndicator = false
    @State private var showReminders = false
    @State private var showHealthExport = false
    /// 长按 + :语音直达(说一句话 → LLM 意图分类 → 打开对应入口)。
    @State private var showVoiceCommand = false
    /// 语音直达「拍药盒」:RootView 层直接弹 MedicationScanFlow,不绕日记 sheet。
    @State private var showMedicationScan = false
    /// 「记录 · 药品库」:sheet + NavigationStack 形态的药品清单管理页。
    @State private var showMedicationLibrary = false

    /// 语音意图 → 打开对应新建入口(与 RecordSheet onPick 的路由一一对应)。
    private func route(_ intent: VoiceIntent) {
        switch intent {
        case .diary:      diaryDirectWrite = true; showDiary = true
        case .medication: showMedicationScan = true
        case .symptom:    showSymptomStart = true
        case .indicator:  showIndicator = true
        case .archive:    activeFlow = .archive
        case .export:     showHealthExport = true
        case .reminder:   showReminders = true
        }
    }

    /// 统一的 tab 切换入口:按方向设定 pushEdge,再带动画改 tab。
    /// 所有改 tab 的地方都走这里,保证过渡方向正确。
    private func select(_ newTab: TjTab) {
        guard newTab != tab else { return }
        pushEdge = newTab.index > tab.index ? .trailing : .leading
        withAnimation(.easeInOut(duration: 0.26)) { tab = newTab }
    }

    var body: some View {
        VStack(spacing: 0) {
            Group {
                switch tab {
                case .home:    HomeView(onTapArchive: { kind in
                    pendingRecordsFilter = kind
                    select(.records)
                })
                case .records: ArchiveListView(initialFilter: pendingRecordsFilter)
                case .trend:   TrendsView()
                case .me:      MeView()
                }
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .id(tab)
            .transition(.push(from: pushEdge))

            TabBar(active: tab,
                   onTap: {
                       // 通过底部 tab 进记录页时清空预选,只有报告档案卡才带 .report 进入。
                       if $0 == .records { pendingRecordsFilter = nil }
                       select($0)
                   },
                   onTapRecord: { showRecordSheet = true },
                   onLongPressRecord: { showVoiceCommand = true })
        }
        .background(Tj.Palette.sand.ignoresSafeArea())
        // 桌面 Widget 快照:启动后写一次,进后台时再写一次(轻量读库,App Group 未配置则 no-op)。
        .task { WidgetSnapshotRefresher.refresh(in: ctx) }
        .onChange(of: scenePhase) { _, phase in
            if phase == .background { WidgetSnapshotRefresher.refresh(in: ctx) }
        }
        .sheet(isPresented: $showRecordSheet) {
            RecordSheet { kind in
                showRecordSheet = false
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    switch kind {
                    case .quick:     activeFlow = .quick
                    case .archive:   activeFlow = .archive
                    case .symptom:   showSymptomStart = true
                    case .diary:     diaryDirectWrite = false; showDiary = true
                    case .indicator: showIndicator = true
                    case .reminder:  showReminders = true
                    case .healthExport: showHealthExport = true
                    case .medicationLibrary: showMedicationLibrary = true
                    }
                }
            }
        }
        .sheet(isPresented: $showSymptomStart) {
            SymptomStartSheet()
        }
        .sheet(isPresented: $showDiary) {
            DiaryQuickSheet(directWrite: diaryDirectWrite)
        }
        .sheet(isPresented: $showIndicator) {
            // 「拍照识别」入口:关闭手输表单 → 打开指标速记 VL 流程(并入「记录指标」)。
            IndicatorQuickSheet(onRequestCamera: {
                showIndicator = false
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    activeFlow = .quick
                }
            })
        }
        .sheet(isPresented: $showReminders) {
            // 列表页依赖外层 NavigationStack 提供标题栏;sheet 形态补「完成」按钮。
            NavigationStack { RemindersListView(presentedAsSheet: true) }
        }
        .sheet(isPresented: $showMedicationLibrary) {
            NavigationStack { MedicationLibraryView(presentedAsSheet: true) }
        }
        .fullScreenCover(isPresented: $showHealthExport) {
            HealthExportSheet()
        }
        .sheet(isPresented: $showVoiceCommand) {
            VoiceCommandSheet(
                onResolve: { intent in
                    showVoiceCommand = false
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
                        route(intent)
                    }
                },
                onOpenMenu: {
                    showVoiceCommand = false
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
                        showRecordSheet = true
                    }
                }
            )
        }
        .fullScreenCover(isPresented: $showMedicationScan) {
            MedicationScanFlow(
                onSave: { meds, images in
                    MedicationArchiver.archive(medications: meds, images: images, in: ctx)
                },
                onClose: { showMedicationScan = false }
            )
        }
#if os(iOS)
        .fullScreenCover(item: $activeFlow) { flow in
            switch flow {
            case .quick:
                QuickRegionCaptureFlow(onClose: { activeFlow = nil })
            case .archive:
                UnifiedCaptureFlow(onClose: { activeFlow = nil })
            }
        }
#else
        .sheet(item: $activeFlow) { flow in
            switch flow {
            case .quick:
                QuickRegionCaptureFlow(onClose: { activeFlow = nil })
            case .archive:
                UnifiedCaptureFlow(onClose: { activeFlow = nil })
            }
        }
#endif
    }
}

private struct TabBar: View {
    let active: TjTab
    let onTap: (TjTab) -> Void
    let onTapRecord: () -> Void
    let onLongPressRecord: () -> Void

    @Namespace private var indicatorNS
    /// + 号按压态(长按手势驱动的缩放视觉,代替 ButtonStyle)。
    @State private var recordPressing = false

    private let cornerRadius: CGFloat = 22
    private let slotHeight: CGFloat = 34

    var body: some View {
        HStack(alignment: .bottom, spacing: 0) {
            tabItem(.home)
            tabItem(.records)
            recordSlot
            tabItem(.trend)
            tabItem(.me)
        }
        .padding(.horizontal, 4)
        .padding(.top, 10)
        .padding(.bottom, 6)
        .background(barBackground)
        .animation(.spring(response: 0.35, dampingFraction: 0.75), value: active)
    }

    private var barBackground: some View {
        UnevenRoundedRectangle(
            topLeadingRadius: cornerRadius,
            bottomLeadingRadius: 0,
            bottomTrailingRadius: 0,
            topTrailingRadius: cornerRadius,
            style: .continuous
        )
        .fill(Tj.Palette.paper)
        .overlay(alignment: .top) {
            Rectangle()
                .fill(Tj.Palette.lineSoft)
                .frame(height: 1)
        }
        .shadow(color: Tj.Palette.shadow.opacity(0.07), radius: 10, x: 0, y: -2)
    }

    private func tabItem(_ t: TjTab) -> some View {
        let isActive = active == t
        return Button { onTap(t) } label: {
            VStack(spacing: 4) {
                ZStack {
                    if isActive {
                        Capsule()
                            .fill(Tj.Palette.sand2)
                            .frame(width: 44, height: slotHeight - 6)
                            .matchedGeometryEffect(id: "tabIndicator", in: indicatorNS)
                    }
                    Image(systemName: t.icon)
                        .font(.tjScaled( 18, weight: isActive ? .semibold : .regular))
                }
                .frame(width: 50, height: slotHeight)

                Text(t.label)
                    .font(.tjScaled( 11, weight: isActive ? .semibold : .regular))
            }
            .foregroundStyle(isActive ? Tj.Palette.ink : Tj.Palette.text3)
            .frame(maxWidth: .infinity)
            .contentShape(Rectangle())
        }
        .buttonStyle(TabPressStyle())
    }

    /// + 号:点按 → 新建菜单;长按 → 语音直达。
    /// 不用 Button + simultaneousGesture(长按成功后松手仍可能触发 tap 二次弹菜单),
    /// 改为 tap / longPress 双手势 + onPressingChanged 驱动按压缩放。
    private var recordSlot: some View {
        VStack(spacing: 4) {
            ZStack {
                Circle()
                    .fill(Tj.Palette.ink)
                    .overlay(
                        Circle()
                            .strokeBorder(Tj.Palette.paper, lineWidth: 2)
                    )
                    .shadow(color: Tj.Palette.shadow.opacity(0.20),
                            radius: 5, x: 0, y: 2)

                Image(systemName: "plus")
                    .font(.tjScaled( 16, weight: .semibold))
                    .foregroundStyle(Tj.Palette.paper)
            }
            .frame(width: slotHeight, height: slotHeight)

            Text("新建")
                .font(.tjScaled( 11, weight: .semibold))
                .foregroundStyle(Tj.Palette.ink)
        }
        .frame(maxWidth: .infinity)
        .contentShape(Rectangle())
        .scaleEffect(recordPressing ? 0.92 : 1.0)
        .animation(.spring(response: 0.25, dampingFraction: 0.7), value: recordPressing)
        .onTapGesture { onTapRecord() }
        .onLongPressGesture(minimumDuration: 0.45) {
            UIImpactFeedbackGenerator(style: .medium).impactOccurred()
            onLongPressRecord()
        } onPressingChanged: { pressing in
            recordPressing = pressing
        }
        .accessibilityElement(children: .combine)
        .accessibilityLabel("新建")
        .accessibilityHint("轻点打开新建菜单,长按语音直达")
    }
}
// 你好
private struct TabPressStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .scaleEffect(configuration.isPressed ? 0.92 : 1.0)
            .animation(.spring(response: 0.25, dampingFraction: 0.7),
                       value: configuration.isPressed)
    }
}

#Preview {
    RootView()
}
