import SwiftUI
import SwiftData

let customMetricIconChoices: [String] = [
    "circle.fill",
    "drop.fill",
    "flame.fill",
    "bolt.fill",
    "leaf.fill",
    "pills.fill",
    "gauge.high",
    "moon.fill",
]

/// 名称冲突判定结果。`detectNameConflict` 返回此值用于 UI 警告。
enum CustomMetricNameConflict: Equatable {
    case none
    case builtin(String)         // 撞到 MonitorMetric.displayName
    case existingCustom(String)  // 撞到其他 CustomMonitorMetric.name

    var warningText: String {
        switch self {
        case .none:                 return ""
        case .builtin(let n):       return String(appLoc: "「\(n)」是内置指标的名字 — 录入 grid 里会出现两个同名块")
        case .existingCustom(let n):return String(appLoc: "已经有一个叫「\(n)」的自定义指标")
        }
    }
}

/// 纯函数:给定 candidate name + 现有 customs + 编辑时排除的 seriesKey,返回冲突类型。
/// 抽离方便单测,不依赖 SwiftData 上下文。
func detectNameConflict(
    candidate: String,
    customs: [CustomMonitorMetric],
    excludingSeriesKey: String? = nil
) -> CustomMetricNameConflict {
    let trimmed = candidate.trimmingCharacters(in: .whitespaces)
    guard !trimmed.isEmpty else { return .none }

    if MonitorMetric.allCases.contains(where: { $0.displayName == trimmed }) {
        return .builtin(trimmed)
    }
    for c in customs where c.seriesKey != excludingSeriesKey && c.name == trimmed {
        return .existingCustom(trimmed)
    }
    return .none
}

/// 自定义长期监测指标的 create / edit / delete sheet。
struct CustomMetricEditor: View {
    @Environment(\.modelContext) private var ctx
    @Environment(\.dismiss) private var dismiss

    /// nil = 新建;非 nil = 编辑现有
    let existing: CustomMonitorMetric?
    /// 保存或删除后回调,parent 可借此 setSelectedCustom(metric? ) 触发后续 UI
    var onSaved: (CustomMonitorMetric?) -> Void

    @Query private var allCustoms: [CustomMonitorMetric]

    @State private var name: String = ""
    @State private var unit: String = ""
    @State private var lower: String = ""
    @State private var upper: String = ""
    @State private var icon: String = "circle.fill"
    @State private var hydrated = false
    @State private var showDeleteConfirm = false

    private var trimmedName: String { name.trimmingCharacters(in: .whitespaces) }
    private var trimmedUnit: String { unit.trimmingCharacters(in: .whitespaces) }
    private var canSubmit: Bool { !trimmedName.isEmpty }

    private var nameConflict: CustomMetricNameConflict {
        detectNameConflict(
            candidate: name,
            customs: allCustoms,
            excludingSeriesKey: existing?.seriesKey
        )
    }

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

            header
                .padding(.horizontal, 20)
                .padding(.bottom, 16)

            ScrollView(showsIndicators: false) {
                VStack(alignment: .leading, spacing: 18) {
                    nameSection
                    unitSection
                    rangeRow
                    iconSection
                    if existing != nil {
                        deleteButton
                    }
                }
                .padding(.horizontal, 20)
                .padding(.bottom, 20)
            }

            footer
        }
        .background(
            Tj.Palette.sand
                .clipShape(RoundedRectangle(cornerRadius: Tj.Radius.xl, style: .continuous))
                .ignoresSafeArea(edges: .bottom)
        )
        .presentationDetents([.medium, .large])
        .presentationDragIndicator(.hidden)
        .presentationBackground(Tj.Palette.sand)
        .presentationCornerRadius(Tj.Radius.xl)
        .onAppear { hydrate() }
    }

    private var header: some View {
        HStack {
            Text(existing == nil ? "新建自定义指标" : "编辑「\(existing!.name)」")
                .font(.tjH2())
                .foregroundStyle(Tj.Palette.text)
            Spacer()
            if existing == nil {
                Text("保存后会出现在录入选项里")
                    .font(.tjScaled( 11))
                    .foregroundStyle(Tj.Palette.text3)
            }
        }
    }

    private var nameSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            sectionLabel(String(appLoc: "名称"))
            TextField("例如:腰围 / 步数 / 睡眠时长", text: $name)
                .padding(.horizontal, 14).padding(.vertical, 12)
                .background(fieldBg)
                .overlay(
                    RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                        .strokeBorder(
                            nameConflict == .none ? Tj.Palette.line : Tj.Palette.amber,
                            lineWidth: 1
                        )
                )
            if nameConflict != .none {
                HStack(spacing: 6) {
                    Image(systemName: "exclamationmark.triangle.fill")
                        .font(.tjScaled( 11))
                        .foregroundStyle(Tj.Palette.amber)
                    Text(nameConflict.warningText)
                        .font(.tjScaled( 11))
                        .foregroundStyle(Tj.Palette.amber)
                        .fixedSize(horizontal: false, vertical: true)
                    Spacer(minLength: 0)
                }
            }
        }
    }

    private var unitSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            sectionLabel(String(appLoc: "单位(可选)"))
            TextField("例如:cm / 步 / 小时", text: $unit)
                .autocorrectionDisabled()
                .padding(.horizontal, 14).padding(.vertical, 12)
                .background(fieldBg).overlay(fieldBorder)
        }
    }

    private var rangeRow: some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack {
                sectionLabel(String(appLoc: "参考范围(可选)"))
                Spacer()
                Text("用于自动判定 正常/偏高/偏低")
                    .font(.tjScaled( 10))
                    .foregroundStyle(Tj.Palette.text3)
            }
            HStack(spacing: 12) {
                rangeField(label: String(appLoc: "下限"), value: $lower, placeholder: "70")
                Text("—").foregroundStyle(Tj.Palette.text3)
                rangeField(label: String(appLoc: "上限"), value: $upper, placeholder: "90")
            }
        }
    }

    private func rangeField(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( 16, weight: .medium, design: .monospaced))
                .padding(.horizontal, 12).padding(.vertical, 10)
                .background(fieldBg).overlay(fieldBorder)
        }
    }

    private var iconSection: some View {
        VStack(alignment: .leading, spacing: 8) {
            sectionLabel(String(appLoc: "图标"))
            LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 8), count: 4),
                      spacing: 8) {
                ForEach(customMetricIconChoices, id: \.self) { sf in
                    Button {
                        icon = sf
                    } label: {
                        Image(systemName: sf)
                            .font(.tjScaled( 20, weight: .medium))
                            .foregroundStyle(icon == sf ? Tj.Palette.paper : Tj.Palette.ink)
                            .frame(maxWidth: .infinity, minHeight: 44)
                            .background(
                                RoundedRectangle(cornerRadius: 10, style: .continuous)
                                    .fill(icon == sf ? Tj.Palette.ink : Tj.Palette.paper)
                            )
                            .overlay(
                                RoundedRectangle(cornerRadius: 10, style: .continuous)
                                    .strokeBorder(Tj.Palette.line, lineWidth: icon == sf ? 0 : 1)
                            )
                    }
                    .buttonStyle(.plain)
                }
            }
        }
    }

    private var deleteButton: some View {
        Button(role: .destructive) {
            showDeleteConfirm = true
        } label: {
            HStack {
                Image(systemName: "trash")
                Text("删除这项自定义指标")
            }
            .font(.tjScaled( 13, weight: .semibold))
            .foregroundStyle(Tj.Palette.brick)
            .frame(maxWidth: .infinity)
            .padding(.vertical, 12)
            .background(
                RoundedRectangle(cornerRadius: Tj.Radius.sm, style: .continuous)
                    .fill(Tj.Palette.brickSoft.opacity(0.5))
            )
        }
        .buttonStyle(.plain)
        .padding(.top, 8)
        .alert(String(appLoc: "删除这项自定义指标?"), isPresented: $showDeleteConfirm) {
            Button(String(appLoc: "删除"), role: .destructive) { deleteMetric() }
            Button(String(appLoc: "取消"), role: .cancel) { }
        } message: {
            Text("删除后不再监测该指标,已记录的历史数据仍保留。")
        }
    }

    private func deleteMetric() {
        guard let m = existing else { return }
        ReminderService.cancel(metricId: m.seriesKey)
        ctx.delete(m)
        try? ctx.save()
        onSaved(nil)
        dismiss()
    }

    private var footer: some View {
        HStack(spacing: 12) {
            Button("取消") { dismiss() }
                .buttonStyle(TjGhostButton(height: 44, fontSize: 15, horizontalPadding: 18))
            Button(existing == nil ? "新建" : "保存") { 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(_ t: String) -> some View {
        Text(t).font(.tjScaled( 12, weight: .semibold)).tracking(0.3)
            .foregroundStyle(Tj.Palette.text2)
    }

    private func hydrate() {
        guard !hydrated, let m = existing else { hydrated = true; return }
        name = m.name; unit = m.unit; icon = m.icon
        lower = m.lowerBound.map { fmt($0) } ?? ""
        upper = m.upperBound.map { fmt($0) } ?? ""
        hydrated = true
    }

    private func submit() {
        guard canSubmit else { return }
        let lo = Double(lower.trimmingCharacters(in: .whitespaces))
        let hi = Double(upper.trimmingCharacters(in: .whitespaces))
        if let m = existing {
            m.name = trimmedName
            m.unit = trimmedUnit
            m.lowerBound = lo
            m.upperBound = hi
            m.icon = icon
            try? ctx.save()
            onSaved(m)
        } else {
            let m = CustomMonitorMetric(
                name: trimmedName,
                unit: trimmedUnit,
                lowerBound: lo,
                upperBound: hi,
                icon: icon
            )
            ctx.insert(m)
            try? ctx.save()
            onSaved(m)
        }
        dismiss()
    }

    private func fmt(_ v: Double) -> String {
        v.truncatingRemainder(dividingBy: 1) == 0
            ? String(format: "%.0f", v)
            : String(format: "%.1f", v)
    }
}
