import SwiftUI
import SwiftData

/// 化验项 free-form 预设(用户当时手动加的辅助列表)。
/// 跟 MonitorMetric 不同——这些是「一次性化验单数值」,不进 Trends,无 seriesKey。
struct IndicatorPreset: Identifiable, Hashable {
    let name: String
    let unit: String
    let range: String
    var id: String { name }
}

private let labPresets: [IndicatorPreset] = [
    .init(name: "LDL-C",     unit: "mmol/L", range: "< 3.40"),
    .init(name: "HDL-C",     unit: "mmol/L", range: "> 1.04"),
    .init(name: "总胆固醇",   unit: "mmol/L", range: "< 5.18"),
    .init(name: "甘油三酯",   unit: "mmol/L", range: "< 1.70"),
    .init(name: "ALT",        unit: "U/L",    range: "9 - 50"),
    .init(name: "尿酸",       unit: "μmol/L", range: "208 - 428"),
    .init(name: "血红蛋白",   unit: "g/L",    range: "130 - 175"),
]

/// 指标录入 sheet,支持 3 种路径:
/// 1. **长期监测预设**(MonitorMetric)— 选预设后字段自动填,带 seriesKey,
///    保存进 Trends。血压拆 2 条 Indicator。
/// 2. **化验项快捷**(labPresets)— 跟 a 类似但只填 name/unit/range 辅助,
///    无 seriesKey,不进 Trends。
/// 3. **自由输入** — name/value/unit/range 全自己填,status 手动选。
struct IndicatorQuickSheet: View {
    /// 「拍照识别」入口回调。由 RootView 注入:关闭本表单 → 打开 QuickRegionCaptureFlow(相机→VL→存)。
    /// nil 时(如 Preview)不显示拍照按钮。
    var onRequestCamera: (() -> Void)? = nil

    /// 从已有指标「再记一条」时的预选目标。nil = 正常空白新建。
    /// seriesKey 命中 MonitorMetric / CustomMonitorMetric → 预选对应预设(保留进趋势 + 自动判异常);
    /// 否则按 name/unit/range 走自由输入预填。数值一律留空,由用户填新读数。
    var prefill: Prefill? = nil

    struct Prefill: Equatable {
        var seriesKey: String?
        var name: String = ""
        var unit: String = ""
        var range: String = ""
    }

    @Environment(\.modelContext) private var ctx
    @Environment(\.dismiss) private var dismiss
    @Query private var profiles: [UserProfile]

    // 状态
    @State private var selectedMonitor: MonitorMetric?
    @State private var selectedLabPreset: IndicatorPreset?

    // 单字段(monitor 单字段、lab、自由)
    @State private var name: String = ""
    @State private var value: String = ""
    @State private var unit: String = ""
    @State private var range: String = ""
    @State private var manualStatus: IndicatorStatus = .normal
    @State private var capturedAt: Date = .now
    @State private var note: String = ""

    // 血压双字段
    @State private var systolic: String = ""
    @State private var diastolic: String = ""

    // 周期性提醒(仅长期监测可用)
    @Query private var allReminders: [MetricReminder]
    @State private var reminderEnabled: Bool = false
    @State private var reminderTime: Date = Self.defaultReminderTime
    @State private var reminderWeekdays: Set<Int> = Set(1...7)
    @State private var reminderHydratedFor: String? = nil
    @State private var notifAuthBlocked: Bool = false

    // 自定义指标
    @Query(sort: \CustomMonitorMetric.createdAt, order: .reverse)
    private var customMetrics: [CustomMonitorMetric]
    @State private var selectedCustom: CustomMonitorMetric?
    @State private var editingCustom: CustomMetricEditTarget?

    // 隐藏管理 sheet 触发态
    @State private var showHiddenSheet: Bool = false

    // 「再记一条」预选只应用一次
    @State private var didApplyPrefill = false

    // 顶部搜索:点放大镜展开搜索框,按名实时过滤长期监测预设 / 自定义指标 / 化验项快捷。
    @State private var searchingMetrics = false
    @State private var metricQuery = ""

    private var isSearchingMetrics: Bool {
        !metricQuery.trimmingCharacters(in: .whitespaces).isEmpty
    }
    private var filteredMonitorMetrics: [MonitorMetric] {
        let q = metricQuery.trimmingCharacters(in: .whitespaces)
        guard !q.isEmpty else { return visibleMonitorMetrics }
        return visibleMonitorMetrics.filter { $0.displayName.localizedCaseInsensitiveContains(q) }
    }
    private var filteredCustomMetrics: [CustomMonitorMetric] {
        let q = metricQuery.trimmingCharacters(in: .whitespaces)
        guard !q.isEmpty else { return customMetrics }
        return customMetrics.filter { $0.name.localizedCaseInsensitiveContains(q) }
    }
    private var filteredLabPresets: [IndicatorPreset] {
        let q = metricQuery.trimmingCharacters(in: .whitespaces)
        guard !q.isEmpty else { return labPresets }
        return labPresets.filter { $0.name.localizedCaseInsensitiveContains(q) }
    }

    private static var defaultReminderTime: Date {
        Calendar.current.date(bySettingHour: 8, minute: 0, second: 0, of: .now) ?? .now
    }

    private var profile: UserProfile? { profiles.first }

    private var isBP: Bool { selectedMonitor == .bloodPressure }
    private var isLongTermMetric: Bool { selectedMonitor != nil || selectedCustom != nil }
    private var isCustomMonitor: Bool { selectedCustom != nil }

    /// 当前长期监测的稳定 key,用于 reminder 关联和 .task(id:) hydrate 触发。
    /// 血压用 metric.rawValue;custom 用 seriesKey;其他单字段 monitor 用 rawValue;非长期 nil。
    private var longTermKey: String? {
        if let m = selectedMonitor { return m.rawValue }
        if let cm = selectedCustom { return cm.seriesKey }
        return nil
    }

    private var longTermDisplayName: String? {
        selectedMonitor?.displayName ?? selectedCustom?.name
    }

    /// 数值类指标(血压 / 长期监测 / 自定义)要求填合法数字且在合理范围;
    /// 化验 / 手动自由值允许非数字(如「阴性」「++」「未见异常」)。
    /// 返回 nil = 通过;否则为给用户看的一句话原因。脏数据会直接画进趋势图,这里挡在入口。
    private var numericValidationError: String? {
        func check(_ s: String, min: Double, max: Double, field: String) -> String? {
            let t = s.trimmingCharacters(in: .whitespaces)
            guard !t.isEmpty else { return nil }          // 空值交给下面的非空判断兜底
            guard let v = Double(t), v.isFinite else { return String(appLoc: "\(field)请填数字") }
            guard v >= min, v <= max else { return String(appLoc: "\(field)数值超出合理范围") }
            return nil
        }
        if isBP {
            return check(systolic, min: 30, max: 350, field: String(appLoc: "收缩压"))
                ?? check(diastolic, min: 20, max: 250, field: String(appLoc: "舒张压"))
        }
        if isLongTermMetric {   // 长期监测预设 / 自定义:必须是正数
            return check(value, min: 0.0001, max: 1_000_000, field: String(appLoc: "数值"))
        }
        return nil   // 自由输入(化验 / 手动)允许非数字
    }

    private var canSubmit: Bool {
        guard numericValidationError == nil else { return false }
        if isBP {
            return !systolic.trimmingCharacters(in: .whitespaces).isEmpty &&
                   !diastolic.trimmingCharacters(in: .whitespaces).isEmpty
        }
        return !name.trimmingCharacters(in: .whitespaces).isEmpty &&
               !value.trimmingCharacters(in: .whitespaces).isEmpty
    }

    var body: some View {
        VStack(spacing: 0) {
            handle
            header

            ScrollView(showsIndicators: false) {
                VStack(alignment: .leading, spacing: 20) {
                    cameraEntrySection
                    monitorGridSection
                    labPresetSection
                    Divider().padding(.vertical, 4)

                    if isBP {
                        bpFieldSection
                    } else {
                        nameSection
                        valueRow
                        rangeSection
                        if isLongTermMetric {
                            autoStatusHint
                        } else {
                            statusSection
                        }
                    }
                    if let validationError = numericValidationError {
                        validationHint(validationError)
                    }

                    timeSection
                    noteSection
                    if isLongTermMetric {
                        reminderSection
                    }
                }
                .padding(.horizontal, 20)
                .padding(.bottom, 20)
            }

            footer
        }
        .onAppear { applyPrefillIfNeeded() }
        .task(id: longTermKey) { hydrateReminder() }
        .background(
            Tj.Palette.sand
                .clipShape(RoundedRectangle(cornerRadius: Tj.Radius.xl, style: .continuous))
                .ignoresSafeArea(edges: .bottom)
        )
        .preferredColorScheme(.light)
        .presentationDetents([.large])
        .presentationDragIndicator(.hidden)
        .presentationBackground(Tj.Palette.sand)
        .presentationCornerRadius(Tj.Radius.xl)
    }

    // MARK: - Sections

    private var handle: some View {
        Capsule()
            .fill(Tj.Palette.line)
            .frame(width: 40, height: 4)
            .padding(.top, 10)
            .padding(.bottom, 14)
    }

    private var header: some View {
        VStack(spacing: 12) {
            HStack(spacing: 10) {
                Text("记录指标")
                    .font(.tjH2())
                    .foregroundStyle(Tj.Palette.text)
                Spacer()
                Text("本地处理 · 永不上传")
                    .font(.tjScaled( 12))
                    .foregroundStyle(Tj.Palette.text3)
                searchToggle
            }
            if searchingMetrics { searchField }
        }
        .padding(.horizontal, 20)
        .padding(.bottom, 16)
    }

    private var searchToggle: some View {
        Button {
            withAnimation(.easeInOut(duration: 0.18)) {
                searchingMetrics.toggle()
                if !searchingMetrics { metricQuery = "" }
            }
        } label: {
            Image(systemName: searchingMetrics ? "xmark" : "magnifyingglass")
                .font(.tjScaled( 14, weight: .semibold))
                .foregroundStyle(Tj.Palette.text)
                .frame(width: 32, height: 32)
                .background(Circle().fill(Tj.Palette.sand2))
        }
        .buttonStyle(.plain)
        .accessibilityLabel(searchingMetrics ? String(appLoc: "关闭搜索") : String(appLoc: "搜索指标"))
    }

    private var searchField: some View {
        HStack(spacing: 8) {
            Image(systemName: "magnifyingglass")
                .font(.tjScaled( 13))
                .foregroundStyle(Tj.Palette.text3)
            TextField(String(appLoc: "搜索指标名"), text: $metricQuery)
                .textInputAutocapitalization(.never)
                .autocorrectionDisabled()
                .foregroundStyle(Tj.Palette.text)
                .tint(Tj.Palette.ink)
            if !metricQuery.isEmpty {
                Button { metricQuery = "" } label: {
                    Image(systemName: "xmark.circle.fill")
                        .foregroundStyle(Tj.Palette.text3)
                }
                .buttonStyle(.plain)
            }
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 10)
        .background(fieldBg)
        .overlay(fieldBorder)
    }

    /// 顶部「拍照识别」入口:并入原「指标速记」。点后由 RootView 切到相机 VL 流程。
    @ViewBuilder
    private var cameraEntrySection: some View {
        if let onRequestCamera {
            VStack(alignment: .leading, spacing: 10) {
                Button {
                    onRequestCamera()
                } label: {
                    HStack(spacing: 12) {
                        ZStack {
                            RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                                .fill(Tj.Palette.brick)
                            Image(systemName: "camera.fill")
                                .font(.tjScaled(18, weight: .medium))
                                .foregroundStyle(Tj.Palette.paper)
                        }
                        .frame(width: 44, height: 44)

                        VStack(alignment: .leading, spacing: 2) {
                            Text("拍照识别")
                                .font(.tjScaled(15, weight: .semibold))
                                .foregroundStyle(Tj.Palette.text)
                            Text("拍化验单,VL 自动读出数值")
                                .font(.tjScaled(12))
                                .foregroundStyle(Tj.Palette.text3)
                        }
                        Spacer()
                        Image(systemName: "chevron.right")
                            .font(.tjScaled(14, weight: .medium))
                            .foregroundStyle(Tj.Palette.text3)
                    }
                    .padding(14)
                    .frame(maxWidth: .infinity)
                    .tjCard(bordered: true)
                }
                .buttonStyle(.plain)

                HStack(spacing: 8) {
                    line
                    Text("或手动填写")
                        .font(.tjScaled(11))
                        .foregroundStyle(Tj.Palette.text3)
                        .fixedSize()
                    line
                }
            }
        }
    }

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

    private var monitorGridSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                sectionLabel(String(appLoc: "长期监测(进趋势)"))
                Spacer()
                if !hiddenSet.isEmpty {
                    hiddenCountChip
                }
            }
            let columns = [GridItem(.flexible()), GridItem(.flexible())]
            LazyVGrid(columns: columns, spacing: 8) {
                ForEach(filteredMonitorMetrics) { m in
                    monitorTile(m)
                }
                ForEach(filteredCustomMetrics) { cm in
                    customTile(cm)
                }
                // 搜索态下不显示「自定义(新建)」格,聚焦过滤结果。
                if !isSearchingMetrics { addCustomTile }
            }
            if isSearchingMetrics, filteredMonitorMetrics.isEmpty, filteredCustomMetrics.isEmpty {
                Text("没有匹配的长期监测指标")
                    .font(.tjScaled( 12))
                    .foregroundStyle(Tj.Palette.text3)
            }
        }
        .sheet(isPresented: $showHiddenSheet) {
            HiddenMonitorRestoreSheet(
                hiddenMetrics: hiddenMonitorMetrics,
                onRestore: { unhideMonitor($0) }
            )
        }
        .sheet(item: $editingCustom) { target in
            CustomMetricEditor(existing: target.metric) { saved in
                // 新建后自动选中,删除后清空选择
                if let saved {
                    selectedCustom = saved
                    selectedMonitor = nil
                    selectedLabPreset = nil
                    fillFromCustom(saved)
                } else if selectedCustom?.seriesKey == target.metric?.seriesKey {
                    selectedCustom = nil
                    clearAllFields()
                }
            }
        }
    }

    private func customTile(_ cm: CustomMonitorMetric) -> some View {
        let selected = selectedCustom?.seriesKey == cm.seriesKey
        return Button {
            applyCustom(cm)
        } label: {
            HStack(spacing: 10) {
                Image(systemName: cm.icon)
                    .font(.tjScaled( 18, weight: .medium))
                    .foregroundStyle(selected ? Tj.Palette.paper : Tj.Palette.ink)
                    .frame(width: 32, height: 32)
                    .background(Circle().fill(selected ? Tj.Palette.ink : Tj.Palette.leafSoft))

                VStack(alignment: .leading, spacing: 1) {
                    Text(cm.name)
                        .font(.tjScaled( 14, weight: selected ? .semibold : .medium))
                        .foregroundStyle(selected ? Tj.Palette.paper : Tj.Palette.text)
                        .lineLimit(1)
                    Text("自定义")
                        .font(.tjScaled( 9, design: .monospaced))
                        .foregroundStyle(selected ? Tj.Palette.paper.opacity(0.7) : Tj.Palette.text3)
                }
                Spacer()
            }
            .padding(.horizontal, 10)
            .padding(.vertical, 10)
            .background(
                RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                    .fill(selected ? Tj.Palette.ink : Tj.Palette.paper)
            )
            .overlay(
                RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                    .strokeBorder(Tj.Palette.line, lineWidth: selected ? 0 : 1)
            )
        }
        .buttonStyle(.plain)
        .contextMenu {
            // 单一入口:进编辑器既能改也能删(编辑器内含删除按钮)。
            // 旧实现两项 action 完全相同,第二项却标红 trash「编辑/删除」,看似直接删除实则打开编辑器,误导。
            Button { editingCustom = CustomMetricEditTarget(metric: cm) } label: {
                Label("编辑 / 删除", systemImage: "pencil")
            }
        }
    }

    private var addCustomTile: some View {
        Button {
            editingCustom = CustomMetricEditTarget(metric: nil)
        } label: {
            HStack(spacing: 10) {
                Image(systemName: "plus")
                    .font(.tjScaled( 18, weight: .semibold))
                    .foregroundStyle(Tj.Palette.text2)
                    .frame(width: 32, height: 32)
                    .background(
                        Circle().strokeBorder(Tj.Palette.line, lineWidth: 1, antialiased: true)
                    )
                Text("自定义")
                    .font(.tjScaled( 14, weight: .medium))
                    .foregroundStyle(Tj.Palette.text2)
                Spacer()
            }
            .padding(.horizontal, 10)
            .padding(.vertical, 10)
            .background(
                RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                    .fill(Tj.Palette.sand2.opacity(0.5))
            )
            .overlay(
                RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                    .strokeBorder(Tj.Palette.line.opacity(0.6),
                                  style: StrokeStyle(lineWidth: 1, dash: [4, 3]))
            )
        }
        .buttonStyle(.plain)
    }

    private func monitorTile(_ m: MonitorMetric) -> some View {
        let selected = selectedMonitor == m
        return Button {
            applyMonitor(m)
        } label: {
            HStack(spacing: 10) {
                Image(systemName: m.icon)
                    .font(.tjScaled( 18, weight: .medium))
                    .foregroundStyle(selected ? Tj.Palette.paper : Tj.Palette.ink)
                    .frame(width: 32, height: 32)
                    .background(Circle().fill(selected ? Tj.Palette.ink : Tj.Palette.amber.opacity(0.25)))

                Text(m.displayName)
                    .font(.tjScaled( 14, weight: selected ? .semibold : .medium))
                    .foregroundStyle(selected ? Tj.Palette.paper : Tj.Palette.text)
                Spacer()
            }
            .padding(.horizontal, 10)
            .padding(.vertical, 10)
            .background(
                RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                    .fill(selected ? Tj.Palette.ink : Tj.Palette.paper)
            )
            .overlay(
                RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                    .strokeBorder(Tj.Palette.line, lineWidth: selected ? 0 : 1)
            )
        }
        .buttonStyle(.plain)
        .contextMenu {
            Button(role: .destructive) {
                hideMonitor(m)
            } label: {
                Label("隐藏", systemImage: "eye.slash")
            }
        }
    }

    @ViewBuilder
    private var labPresetSection: some View {
        // 搜索且化验项无匹配:整段隐藏(避免只剩一个空标题)。
        if !(isSearchingMetrics && filteredLabPresets.isEmpty) {
            VStack(alignment: .leading, spacing: 8) {
                sectionLabel(String(appLoc: "化验项快捷(不进趋势)"))
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 8) {
                        ForEach(filteredLabPresets) { p in
                            chip(p.name, selected: selectedLabPreset == p) {
                                applyLab(p)
                            }
                        }
                    }
                }
            }
        }
    }

    private var bpFieldSection: some View {
        VStack(alignment: .leading, spacing: 12) {
            HStack {
                sectionLabel(String(appLoc: "收缩 / 舒张"))
                Spacer()
                bpRangeHint
            }
            HStack(spacing: 12) {
                bpField(label: String(appLoc: "收缩压"), value: $systolic, placeholder: "120")
                Text("/").font(.tjScaled( 22, weight: .light)).foregroundStyle(Tj.Palette.text3)
                bpField(label: String(appLoc: "舒张压"), value: $diastolic, placeholder: "80")
                Text("mmHg").foregroundStyle(Tj.Palette.text3)
            }
            bpStatusChips
        }
    }

    private func bpField(label: String, value: Binding<String>, placeholder: String) -> some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(label).font(.tjScaled( 11)).foregroundStyle(Tj.Palette.text3)
            TextField(placeholder, text: value)
                .keyboardType(.decimalPad)
                .font(.tjScaled( 20, weight: .semibold, design: .monospaced))
                .foregroundStyle(Tj.Palette.text)
                .tint(Tj.Palette.ink)
                .multilineTextAlignment(.center)
                .padding(.vertical, 10)
                .frame(width: 90)
                .background(fieldBg)
                .overlay(fieldBorder)
        }
    }

    private var bpRangeHint: some View {
        let sysRange = MonitorMetric.bloodPressure.effectiveRange(
            for: MonitorMetric.bloodPressure.fields[0], profile: profile)
        let diasRange = MonitorMetric.bloodPressure.effectiveRange(
            for: MonitorMetric.bloodPressure.fields[1], profile: profile)
        let personalized = MonitorMetric.bloodPressure.isRangePersonalized(
            for: MonitorMetric.bloodPressure.fields[0], profile: profile)
        let rangeText = "\(formatRange(sysRange)) / \(formatRange(diasRange))"
        return HStack(spacing: 4) {
            Text(rangeText)
                .font(.tjScaled( 11, design: .monospaced))
                .foregroundStyle(Tj.Palette.text3)
            if personalized, let age = profile?.age {
                Text("· 按\(age)岁调整")
                    .font(.tjScaled( 10))
                    .foregroundStyle(Tj.Palette.amber)
            }
        }
    }

    private var bpStatusChips: some View {
        HStack(spacing: 8) {
            if let s = computedBPStatus(.systolic) {
                statusBadge(String(appLoc: "收缩 ") + s.label, color: s.color)
            }
            if let s = computedBPStatus(.diastolic) {
                statusBadge(String(appLoc: "舒张 ") + s.label, color: s.color)
            }
            Spacer()
        }
    }

    private var nameSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            sectionLabel(String(appLoc: "指标名"))
            TextField("例如:血红蛋白", text: $name)
                .textInputAutocapitalization(.never)
                .foregroundStyle(Tj.Palette.text)
                .tint(Tj.Palette.ink)
                .padding(.horizontal, 14)
                .padding(.vertical, 12)
                .background(fieldBg)
                .overlay(fieldBorder)
                .onChange(of: name) { _, _ in
                    if let p = selectedLabPreset, p.name != name {
                        selectedLabPreset = nil
                    }
                }
                .disabled(isLongTermMetric)
                .opacity(isLongTermMetric ? 0.6 : 1)
        }
    }

    private var valueRow: some View {
        HStack(alignment: .top, spacing: 12) {
            VStack(alignment: .leading, spacing: 8) {
                sectionLabel(String(appLoc: "数值"))
                TextField(monitorFieldPlaceholder, text: $value)
                    .keyboardType(.decimalPad)
                    .font(.tjScaled( 18, weight: .semibold, design: .monospaced))
                    .foregroundStyle(Tj.Palette.text)
                    .tint(Tj.Palette.ink)
                    .padding(.horizontal, 14)
                    .padding(.vertical, 12)
                    .background(fieldBg)
                    .overlay(fieldBorder)
            }
            VStack(alignment: .leading, spacing: 8) {
                sectionLabel(String(appLoc: "单位"))
                TextField("mmol/L", text: $unit)
                    .textInputAutocapitalization(.never)
                    .autocorrectionDisabled()
                    .foregroundStyle(Tj.Palette.text)
                    .tint(Tj.Palette.ink)
                    .padding(.horizontal, 14)
                    .padding(.vertical, 12)
                    .background(fieldBg)
                    .overlay(fieldBorder)
                    .disabled(isLongTermMetric)
                    .opacity(isLongTermMetric ? 0.6 : 1)
            }
            .frame(maxWidth: 130)
        }
    }

    private var rangeSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                sectionLabel(String(appLoc: "参考范围"))
                Spacer()
                if let m = selectedMonitor, m != .bloodPressure {
                    monitorRangeHint(m)
                }
            }
            TextField("例如:< 3.40 或 3.9 - 6.1", text: $range)
                .textInputAutocapitalization(.never)
                .autocorrectionDisabled()
                .foregroundStyle(Tj.Palette.text)
                .tint(Tj.Palette.ink)
                .padding(.horizontal, 14)
                .padding(.vertical, 12)
                .background(fieldBg)
                .overlay(fieldBorder)
                .disabled(isLongTermMetric)
                .opacity(isLongTermMetric ? 0.6 : 1)
        }
    }

    private func monitorRangeHint(_ m: MonitorMetric) -> some View {
        let personalized = m.isRangePersonalized(for: m.fields[0], profile: profile)
        return HStack(spacing: 4) {
            if personalized, let age = profile?.age {
                Text("按\(age)岁调整")
                    .font(.tjScaled( 10))
                    .foregroundStyle(Tj.Palette.amber)
            }
        }
    }

    private var statusSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            sectionLabel(String(appLoc: "状态"))
            HStack(spacing: 8) {
                statusChip(.normal, label: String(appLoc: "正常"), color: Tj.Palette.leaf)
                statusChip(.high,   label: String(appLoc: "偏高 ↑"), color: Tj.Palette.brick)
                statusChip(.low,    label: String(appLoc: "偏低 ↓"), color: Tj.Palette.amber)
            }
        }
    }

    private var autoStatusHint: some View {
        let auto = computedSingleStatus
        return HStack(spacing: 8) {
            sectionLabel(String(appLoc: "状态(按数值自动判)"))
            if let s = auto {
                statusBadge(s.label, color: s.color)
            } else {
                Text("待输入")
                    .font(.tjScaled( 12))
                    .foregroundStyle(Tj.Palette.text3)
            }
        }
    }

    private var timeSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            sectionLabel(String(appLoc: "测量时间"))
            DatePicker("", selection: $capturedAt, in: ...Date.now)
                .datePickerStyle(.compact)
                .labelsHidden()
        }
    }

    private var noteSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            sectionLabel(String(appLoc: "备注(可选)"))
            TextField("例如:空腹采血", text: $note, axis: .vertical)
                .lineLimit(1...3)
                .foregroundStyle(Tj.Palette.text)
                .tint(Tj.Palette.ink)
                .padding(.horizontal, 14)
                .padding(.vertical, 12)
                .background(fieldBg)
                .overlay(fieldBorder)
        }
    }

    // MARK: - 周期提醒

    private var reminderSection: some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                sectionLabel(String(appLoc: "周期提醒"))
                Spacer()
                Toggle("", isOn: $reminderEnabled)
                    .labelsHidden()
                    .tint(Tj.Palette.ink)
                    .onChange(of: reminderEnabled) { _, on in
                        if on { Task { await requestNotifAuthIfNeeded() } }
                    }
            }

            if reminderEnabled {
                VStack(alignment: .leading, spacing: 12) {
                    HStack {
                        Text("时间")
                            .font(.tjScaled( 13))
                            .foregroundStyle(Tj.Palette.text2)
                        Spacer()
                        DatePicker("", selection: $reminderTime,
                                   displayedComponents: .hourAndMinute)
                            .datePickerStyle(.compact)
                            .labelsHidden()
                    }

                    VStack(alignment: .leading, spacing: 6) {
                        HStack {
                            Text("频率")
                                .font(.tjScaled( 13))
                                .foregroundStyle(Tj.Palette.text2)
                            Spacer()
                            Text(reminderFrequencyLabel)
                                .font(.tjScaled( 12))
                                .foregroundStyle(Tj.Palette.text3)
                        }
                        weekdayPickerRow
                        HStack(spacing: 8) {
                            quickFreqChip(String(appLoc: "每天")) {
                                reminderWeekdays = Set(1...7)
                            }
                            quickFreqChip(String(appLoc: "工作日")) {
                                reminderWeekdays = Set([2, 3, 4, 5, 6])
                            }
                            quickFreqChip(String(appLoc: "周末")) {
                                reminderWeekdays = Set([1, 7])
                            }
                        }
                    }

                    if notifAuthBlocked {
                        Text("⚠️ 通知权限已关闭,去「设置 → 康康 → 通知」打开")
                            .font(.tjScaled( 11))
                            .foregroundStyle(Tj.Palette.brick)
                    } else {
                        Text("本机提醒 · 不发任何数据")
                            .font(.tjScaled( 11))
                            .foregroundStyle(Tj.Palette.text3)
                    }
                }
                .padding(12)
                .background(fieldBg)
                .overlay(fieldBorder)
            }
        }
    }

    private var reminderFrequencyLabel: String {
        if reminderWeekdays.count == 7 { return String(appLoc: "每天") }
        if reminderWeekdays.isEmpty { return String(appLoc: "未选") }
        let names = [
            String(appLoc: "日"), String(appLoc: "一"), String(appLoc: "二"),
            String(appLoc: "三"), String(appLoc: "四"), String(appLoc: "五"),
            String(appLoc: "六"),
        ]
        let sorted = reminderWeekdays.sorted()
        return String(appLoc: "每周 ") + sorted.map { names[$0 - 1] }.joined()
    }

    private var weekdayPickerRow: some View {
        let names = [
            String(appLoc: "一"), String(appLoc: "二"), String(appLoc: "三"),
            String(appLoc: "四"), String(appLoc: "五"), String(appLoc: "六"),
            String(appLoc: "日"),
        ]
        let weekdayValues = [2, 3, 4, 5, 6, 7, 1]  // 周一到周日(Apple Calendar 编号)
        return HStack(spacing: 6) {
            ForEach(Array(weekdayValues.enumerated()), id: \.offset) { idx, w in
                Button {
                    if reminderWeekdays.contains(w) {
                        reminderWeekdays.remove(w)
                    } else {
                        reminderWeekdays.insert(w)
                    }
                } label: {
                    Text(names[idx])
                        .font(.tjScaled( 13,
                                      weight: reminderWeekdays.contains(w) ? .semibold : .regular))
                        .foregroundStyle(reminderWeekdays.contains(w) ? Tj.Palette.paper : Tj.Palette.text)
                        .frame(maxWidth: .infinity, minHeight: 32)
                        .background(
                            RoundedRectangle(cornerRadius: 8, style: .continuous)
                                .fill(reminderWeekdays.contains(w) ? Tj.Palette.ink : Tj.Palette.paper)
                        )
                        .overlay(
                            RoundedRectangle(cornerRadius: 8, style: .continuous)
                                .strokeBorder(Tj.Palette.line,
                                              lineWidth: reminderWeekdays.contains(w) ? 0 : 1)
                        )
                }
                .buttonStyle(.plain)
            }
        }
    }

    private func quickFreqChip(_ label: String, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Text(label)
                .font(.tjScaled( 11))
                .foregroundStyle(Tj.Palette.text2)
                .padding(.horizontal, 10)
                .padding(.vertical, 4)
                .background(Capsule().fill(Tj.Palette.sand2))
        }
        .buttonStyle(.plain)
    }

    private func hydrateReminder() {
        guard let key = longTermKey else { return }
        if reminderHydratedFor == key { return }
        reminderHydratedFor = key
        if let existing = allReminders.first(where: { $0.metricId == key }) {
            reminderEnabled = existing.enabled
            reminderTime = Calendar.current.date(
                bySettingHour: existing.hour, minute: existing.minute, second: 0, of: .now
            ) ?? Self.defaultReminderTime
            reminderWeekdays = Set(existing.weekdays)
        } else {
            reminderEnabled = false
            reminderTime = Self.defaultReminderTime
            reminderWeekdays = Set(1...7)
        }
    }

    private func requestNotifAuthIfNeeded() async {
        let state = await ReminderService.requestAuthorization()
        notifAuthBlocked = (state == .denied)
        if notifAuthBlocked {
            reminderEnabled = false
        }
    }

    /// submit() 调用,处理提醒:enabled → upsert SwiftData + 调度通知;disabled → 删旧 reminder + 取消通知。
    private func persistReminderIfNeeded() async {
        guard let key = longTermKey, let displayName = longTermDisplayName else { return }
        let existing = allReminders.first(where: { $0.metricId == key })
        let cal = Calendar.current
        let hour = cal.component(.hour, from: reminderTime)
        let minute = cal.component(.minute, from: reminderTime)

        if reminderEnabled && !reminderWeekdays.isEmpty {
            let reminder: MetricReminder
            if let existing {
                existing.enabled = true
                existing.hour = hour
                existing.minute = minute
                existing.weekdays = reminderWeekdays.sorted()
                existing.displayName = displayName
                existing.updatedAt = .now
                reminder = existing
            } else {
                let new = MetricReminder(
                    metricId: key,
                    displayName: displayName,
                    hour: hour,
                    minute: minute,
                    weekdays: reminderWeekdays.sorted(),
                    enabled: true
                )
                ctx.insert(new)
                reminder = new
            }
            try? ctx.save()
            await ReminderService.sync(reminder)
        } else if let existing {
            // 关闭:保留 SwiftData 行,只改 enabled = false,取消通知
            existing.enabled = false
            existing.updatedAt = .now
            try? ctx.save()
            ReminderService.cancel(metricId: key)
        }
    }

    private var footer: some View {
        HStack(spacing: 12) {
            Button("取消") { dismiss() }
                .buttonStyle(TjGhostButton(height: 44, fontSize: 15, horizontalPadding: 18))
            Button("保存到记录") { submit() }
                .buttonStyle(TjPrimaryButton(height: 44, fontSize: 15, horizontalPadding: 18))
                .disabled(!canSubmit)
                .opacity(canSubmit ? 1 : 0.4)
        }
        .padding(.horizontal, 20)
        .padding(.vertical, 14)
        .background(
            Tj.Palette.sand
                .overlay(alignment: .top) {
                    Rectangle().fill(Tj.Palette.lineSoft).frame(height: 1)
                }
        )
    }

    // MARK: - helpers

    private var fieldBg: some View {
        RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
            .fill(Tj.Palette.paper)
    }

    private var fieldBorder: some View {
        RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
            .strokeBorder(Tj.Palette.line, lineWidth: 1)
    }

    private func sectionLabel(_ text: String) -> some View {
        Text(text)
            .font(.tjScaled( 12, weight: .semibold))
            .tracking(0.3)
            .foregroundStyle(Tj.Palette.text2)
    }

    private func chip(_ label: String, selected: Bool, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Text(label)
                .font(.tjScaled( 13, weight: selected ? .semibold : .regular))
                .foregroundStyle(selected ? Tj.Palette.paper : Tj.Palette.text)
                .padding(.horizontal, 14)
                .padding(.vertical, 8)
                .background(Capsule().fill(selected ? Tj.Palette.ink : Tj.Palette.paper))
                .overlay(Capsule().strokeBorder(Tj.Palette.line, lineWidth: selected ? 0 : 1))
        }
        .buttonStyle(.plain)
    }

    private func statusChip(_ value: IndicatorStatus, label: String, color: Color) -> some View {
        let selected = manualStatus == value
        return Button {
            manualStatus = value
        } label: {
            Text(label)
                .font(.tjScaled( 13, weight: selected ? .semibold : .regular))
                .foregroundStyle(selected ? Tj.Palette.paper : color)
                .padding(.horizontal, 14)
                .padding(.vertical, 8)
                .frame(maxWidth: .infinity)
                .background(Capsule().fill(selected ? color : Tj.Palette.paper))
                .overlay(Capsule().strokeBorder(color.opacity(selected ? 0 : 0.5), lineWidth: 1))
        }
        .buttonStyle(.plain)
    }

    private func statusBadge(_ label: String, color: Color) -> some View {
        Text(label)
            .font(.tjScaled( 11, weight: .semibold))
            .foregroundStyle(color)
            .padding(.horizontal, 10)
            .padding(.vertical, 4)
            .background(Capsule().fill(color.opacity(0.18)))
    }

    private var monitorFieldPlaceholder: String {
        selectedMonitor?.fields.first?.placeholder ?? "3.84"
    }

    private func formatRange(_ r: ClosedRange<Double>?) -> String {
        guard let r = r else { return "—" }
        let fmt = { (v: Double) in
            v.truncatingRemainder(dividingBy: 1) == 0
                ? String(format: "%.0f", v) : String(format: "%.1f", v)
        }
        return "\(fmt(r.lowerBound))–\(fmt(r.upperBound))"
    }

    // MARK: - hidden preset 管理

    private var hiddenSet: Set<String> {
        Set(profile?.hiddenPresetMetrics ?? [])
    }

    private var visibleMonitorMetrics: [MonitorMetric] {
        MonitorMetric.allCases.filter { !hiddenSet.contains($0.rawValue) }
    }

    private var hiddenMonitorMetrics: [MonitorMetric] {
        MonitorMetric.allCases.filter { hiddenSet.contains($0.rawValue) }
    }

    private var hiddenCountChip: some View {
        Button {
            showHiddenSheet = true
        } label: {
            HStack(spacing: 3) {
                Text("已隐藏 \(hiddenSet.count)")
                    .font(.tjScaled( 11, weight: .medium))
                Image(systemName: "chevron.right")
                    .font(.tjScaled( 9, weight: .semibold))
            }
            .foregroundStyle(Tj.Palette.text2)
            .padding(.horizontal, 10)
            .padding(.vertical, 4)
            .background(Capsule().fill(Tj.Palette.sand2))
        }
        .buttonStyle(.plain)
    }

    private func hideMonitor(_ m: MonitorMetric) {
        let profile = UserProfileStore.loadOrCreate(in: ctx)
        guard !profile.hiddenPresetMetrics.contains(m.rawValue) else { return }
        profile.hiddenPresetMetrics.append(m.rawValue)
        profile.updatedAt = .now
        try? ctx.save()
        if selectedMonitor == m {
            clearMonitor()
        }
    }

    private func unhideMonitor(_ m: MonitorMetric) {
        guard let profile = profile else { return }
        profile.hiddenPresetMetrics.removeAll { $0 == m.rawValue }
        profile.updatedAt = .now
        try? ctx.save()
        if profile.hiddenPresetMetrics.isEmpty {
            showHiddenSheet = false
        }
    }

    // MARK: - apply preset

    /// 「再记一条」预选:seriesKey 命中长期监测预设 / 自定义指标则选中对应卡片(进趋势 + 自动判异常),
    /// 否则按 name/unit/range 走自由输入。数值不预填——让用户填新读数。只应用一次。
    private func applyPrefillIfNeeded() {
        guard !didApplyPrefill, let p = prefill else { return }
        didApplyPrefill = true
        if let key = p.seriesKey {
            if let m = MonitorMetric.allCases.first(where: { metric in
                metric.fields.contains { $0.seriesKey == key }
            }) {
                applyMonitor(m)
                return
            }
            if let cm = customMetrics.first(where: { $0.seriesKey == key }) {
                applyCustom(cm)
                return
            }
        }
        // 无 seriesKey 或未匹配预设(化验项 / 报告 / 自由指标):自由输入预填,不带 seriesKey,不进趋势。
        name = p.name
        unit = p.unit
        range = p.range
    }

    private func applyMonitor(_ m: MonitorMetric) {
        if selectedMonitor == m {
            // 取消选择
            clearMonitor()
            return
        }
        selectedMonitor = m
        selectedLabPreset = nil
        selectedCustom = nil

        if m == .bloodPressure {
            // 血压走 bp 字段,不动 name/value/unit
            name = m.displayName
            unit = "mmHg"
        } else {
            let f = m.fields[0]
            name = m.displayName
            value = ""
            unit = f.unit
            let r = m.effectiveRange(for: f, profile: profile)
            range = f.rangeText(r)
        }
    }

    private func clearMonitor() {
        selectedMonitor = nil
        name = ""; value = ""; unit = ""; range = ""
        systolic = ""; diastolic = ""
    }

    private func applyLab(_ p: IndicatorPreset) {
        selectedLabPreset = p
        selectedMonitor = nil
        selectedCustom = nil
        systolic = ""; diastolic = ""
        name = p.name
        if unit.trimmingCharacters(in: .whitespaces).isEmpty { unit = p.unit }
        if range.trimmingCharacters(in: .whitespaces).isEmpty { range = p.range }
    }

    private func applyCustom(_ cm: CustomMonitorMetric) {
        if selectedCustom?.seriesKey == cm.seriesKey {
            selectedCustom = nil
            clearAllFields()
            return
        }
        selectedCustom = cm
        selectedMonitor = nil
        selectedLabPreset = nil
        fillFromCustom(cm)
    }

    private func fillFromCustom(_ cm: CustomMonitorMetric) {
        name = cm.name
        value = ""
        unit = cm.unit
        range = cm.rangeText
        systolic = ""; diastolic = ""
    }

    private func clearAllFields() {
        name = ""; value = ""; unit = ""; range = ""
        systolic = ""; diastolic = ""
    }

    // MARK: - auto status

    private var computedSingleStatus: (label: String, color: Color)? {
        guard let v = Double(value.trimmingCharacters(in: .whitespaces)) else { return nil }
        if let m = selectedMonitor, m != .bloodPressure {
            let f = m.fields[0]
            let r = m.effectiveRange(for: f, profile: profile)
            let s = MonitorMetric.status(value: v, in: r)
            return (s.label, s.color)
        }
        if let cm = selectedCustom {
            let s = MonitorMetric.status(value: v, in: cm.referenceRange)
            return (s.label, s.color)
        }
        return nil
    }

    private enum BPSide { case systolic, diastolic }

    private func computedBPStatus(_ side: BPSide) -> (label: String, color: Color)? {
        let text = side == .systolic ? systolic : diastolic
        guard let v = Double(text.trimmingCharacters(in: .whitespaces)) else { return nil }
        let m = MonitorMetric.bloodPressure
        let f = m.fields[side == .systolic ? 0 : 1]
        let r = m.effectiveRange(for: f, profile: profile)
        let s = MonitorMetric.status(value: v, in: r)
        return (s.label, s.color)
    }

    // MARK: - 校验提示

    private func validationHint(_ text: String) -> some View {
        HStack(spacing: 6) {
            Image(systemName: "exclamationmark.circle.fill")
                .font(.tjScaled(11))
                .foregroundStyle(Tj.Palette.brick)
            Text(text)
                .font(.tjScaled(12))
                .foregroundStyle(Tj.Palette.brick)
            Spacer(minLength: 0)
        }
        .transition(.opacity)
    }

    // MARK: - submit

    private func submit() {
        guard canSubmit else { return }

        if isBP {
            saveBP()
        } else if let m = selectedMonitor {
            saveSingleMonitor(m)
        } else if let cm = selectedCustom {
            saveCustom(cm)
        } else {
            saveFreeform()
        }

        Task {
            await persistReminderIfNeeded()
            await MainActor.run { dismiss() }
        }
    }

    private func saveBP() {
        let m = MonitorMetric.bloodPressure
        let sys = Double(systolic.trimmingCharacters(in: .whitespaces)) ?? 0
        let dia = Double(diastolic.trimmingCharacters(in: .whitespaces)) ?? 0
        let sysField = m.fields[0]
        let diaField = m.fields[1]
        let sysRange = m.effectiveRange(for: sysField, profile: profile)
        let diaRange = m.effectiveRange(for: diaField, profile: profile)
        let sysStatus = MonitorMetric.status(value: sys, in: sysRange)
        let diaStatus = MonitorMetric.status(value: dia, in: diaRange)

        let timestamp = capturedAt
        let systolicI = Indicator(
            name: sysField.label,
            value: systolic,
            unit: sysField.unit,
            range: sysField.rangeText(sysRange),
            status: sysStatus,
            note: note.isEmpty ? nil : note,
            capturedAt: timestamp,
            pinned: true,
            seriesKey: sysField.seriesKey
        )
        let diastolicI = Indicator(
            name: diaField.label,
            value: diastolic,
            unit: diaField.unit,
            range: diaField.rangeText(diaRange),
            status: diaStatus,
            note: nil,
            capturedAt: timestamp,
            pinned: true,
            seriesKey: diaField.seriesKey
        )
        ctx.insert(systolicI)
        ctx.insert(diastolicI)
        try? ctx.save()
    }

    private func saveSingleMonitor(_ m: MonitorMetric) {
        let f = m.fields[0]
        let v = Double(value.trimmingCharacters(in: .whitespaces)) ?? 0
        let r = m.effectiveRange(for: f, profile: profile)
        let status = MonitorMetric.status(value: v, in: r)
        let indicator = Indicator(
            name: m.displayName,
            value: value.trimmingCharacters(in: .whitespaces),
            unit: f.unit,
            range: f.rangeText(r),
            status: status,
            note: note.isEmpty ? nil : note,
            capturedAt: capturedAt,
            pinned: true,
            seriesKey: f.seriesKey
        )
        ctx.insert(indicator)
        try? ctx.save()
    }

    private func saveCustom(_ cm: CustomMonitorMetric) {
        let v = Double(value.trimmingCharacters(in: .whitespaces)) ?? 0
        let status = MonitorMetric.status(value: v, in: cm.referenceRange)
        let indicator = Indicator(
            name: cm.name,
            value: value.trimmingCharacters(in: .whitespaces),
            unit: cm.unit,
            range: cm.rangeText,
            status: status,
            note: note.isEmpty ? nil : note,
            capturedAt: capturedAt,
            pinned: true,
            seriesKey: cm.seriesKey
        )
        ctx.insert(indicator)
        try? ctx.save()
    }

    private func saveFreeform() {
        let indicator = Indicator(
            name: name.trimmingCharacters(in: .whitespaces),
            value: value.trimmingCharacters(in: .whitespaces),
            unit: unit.trimmingCharacters(in: .whitespaces),
            range: range.trimmingCharacters(in: .whitespaces),
            status: manualStatus,
            note: note.trimmingCharacters(in: .whitespaces).isEmpty ? nil : note,
            capturedAt: capturedAt
        )
        ctx.insert(indicator)
        try? ctx.save()
    }
}

// MARK: - Status display helpers

private extension IndicatorStatus {
    var label: String {
        switch self {
        case .normal: return String(appLoc: "正常")
        case .high:   return String(appLoc: "偏高 ↑")
        case .low:    return String(appLoc: "偏低 ↓")
        }
    }

    var color: Color {
        switch self {
        case .normal: return Tj.Palette.leaf
        case .high:   return Tj.Palette.brick
        case .low:    return Tj.Palette.amber
        }
    }
}

/// `.sheet(item:)` 要求 Identifiable;包一层避免 CustomMonitorMetric? 不能直接当 binding 用。
struct CustomMetricEditTarget: Identifiable {
    let metric: CustomMonitorMetric?
    var id: String { metric?.seriesKey ?? "_new_" }
}

/// 已隐藏的长期监测预设恢复列表。点"显示"把对应 metric 从 hiddenPresetMetrics 移除。
private struct HiddenMonitorRestoreSheet: View {
    let hiddenMetrics: [MonitorMetric]
    let onRestore: (MonitorMetric) -> Void

    @Environment(\.dismiss) private var dismiss

    var body: some View {
        VStack(spacing: 0) {
            Capsule()
                .fill(Tj.Palette.line)
                .frame(width: 40, height: 4)
                .padding(.top, 10)
                .padding(.bottom, 14)

            HStack {
                Text("已隐藏的长期监测")
                    .font(.tjH2())
                    .foregroundStyle(Tj.Palette.text)
                Spacer()
                Button("完成") { dismiss() }
                    .font(.tjScaled( 14))
                    .foregroundStyle(Tj.Palette.ink)
            }
            .padding(.horizontal, 20)
            .padding(.bottom, 12)

            ScrollView {
                VStack(spacing: 8) {
                    ForEach(hiddenMetrics) { m in
                        row(m)
                    }
                }
                .padding(.horizontal, 20)
                .padding(.bottom, 24)
            }
        }
        .background(Tj.Palette.sand)
        .presentationDetents([.medium])
        .presentationBackground(Tj.Palette.sand)
        .presentationCornerRadius(Tj.Radius.xl)
    }

    private func row(_ m: MonitorMetric) -> some View {
        HStack(spacing: 12) {
            Image(systemName: m.icon)
                .font(.tjScaled( 16, weight: .medium))
                .foregroundStyle(Tj.Palette.ink)
                .frame(width: 32, height: 32)
                .background(Circle().fill(Tj.Palette.amber.opacity(0.25)))

            Text(m.displayName)
                .font(.tjScaled( 15, weight: .medium))
                .foregroundStyle(Tj.Palette.text)

            Spacer()

            Button("显示") {
                onRestore(m)
            }
            .font(.tjScaled( 13, weight: .semibold))
            .foregroundStyle(Tj.Palette.paper)
            .padding(.horizontal, 14)
            .padding(.vertical, 6)
            .background(Capsule().fill(Tj.Palette.ink))
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 10)
        .background(
            RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                .fill(Tj.Palette.paper)
        )
        .overlay(
            RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                .strokeBorder(Tj.Palette.line, lineWidth: 1)
        )
    }
}

#Preview {
    IndicatorQuickSheet()
        .modelContainer(for: [
            Indicator.self, UserProfile.self,
            MetricReminder.self, CustomMonitorMetric.self
        ], inMemory: true)
}
