import SwiftUI
import SwiftData

/// 自由周期提醒的创建 / 编辑表单。
/// `reminder == nil` 为新建;否则为编辑(多一个删除按钮)。
/// 本地 @State 暂存,保存时才写 SwiftData + 调度通知;取消即丢弃。
struct CustomReminderEditSheet: View {
    @Environment(\.modelContext) private var ctx
    @Environment(\.dismiss) private var dismiss

    /// nil = 新建模式。
    let reminder: CustomReminder?
    /// 新建模式下的预填(如从「用药记录」点药进来,预填「吃药:药名」+ 用法备注)。
    /// 编辑模式(reminder != nil)忽略。
    private let prefillTitle: String
    private let prefillNote: String

    @State private var title = ""
    @State private var note = ""
    @State private var pickedTime: Date = .now
    /// 多选频率(每日/每周/每月/每年 可同时勾选)。
    @State private var frequencies: Set<CustomReminder.Frequency> = [.daily]
    @State private var weekdays: Set<Int> = Set(1...7)
    /// 每月多选日期(1...31)。
    @State private var monthDays: Set<Int> = [1]
    @State private var dayOfMonth = 1   // 仅「每年」用
    @State private var month = 1
    @State private var hydrated = false
    @State private var showAuthDeniedAlert = false
    @State private var showDeleteConfirm = false

    /// 常用时间快捷预设(时, 分):早 / 午 / 傍晚 / 睡前。
    private let timePresets: [(h: Int, m: Int)] = [(8, 0), (12, 0), (18, 0), (22, 0)]

    init(reminder: CustomReminder? = nil, prefillTitle: String = "", prefillNote: String = "") {
        self.reminder = reminder
        self.prefillTitle = prefillTitle
        self.prefillNote = prefillNote
    }

    private var isEditing: Bool { reminder != nil }
    private var trimmedTitle: String {
        title.trimmingCharacters(in: .whitespacesAndNewlines)
    }
    private var canSave: Bool {
        guard !trimmedTitle.isEmpty, !frequencies.isEmpty else { return false }
        if frequencies.contains(.weekly) && weekdays.isEmpty { return false }
        if frequencies.contains(.monthly) && monthDays.isEmpty { return false }
        return true
    }

    var body: some View {
        NavigationStack {
            Form {
                Section {
                    TextField(String(appLoc: "做点什么?例:跑步5公里 / 吃2片护肝片"),
                              text: $title, axis: .vertical)
                        .lineLimit(1...3)
                    TextField(String(appLoc: "备注(可选)"), text: $note, axis: .vertical)
                        .lineLimit(1...3)
                        .foregroundStyle(Tj.Palette.text2)
                }

                Section {
                    frequencyChips
                    frequencyDetail
                } header: {
                    Text("重复")
                } footer: {
                    Text("可多选:如同时勾选「每周一三五」+「每月1日」,两种节奏都会提醒。")
                }

                Section {
                    timePresetRow
                    DatePicker(String(appLoc: "时间"), selection: $pickedTime,
                               displayedComponents: .hourAndMinute)
                } header: {
                    Text("时间")
                }

                if isEditing {
                    Section {
                        Button(role: .destructive) { showDeleteConfirm = true } label: {
                            Label(String(appLoc: "删除提醒"), systemImage: "trash")
                        }
                    }
                }
            }
            .scrollContentBackground(.hidden)
            .background(Tj.Palette.sand.ignoresSafeArea())
            .navigationTitle(isEditing ? String(appLoc: "编辑提醒") : String(appLoc: "新建提醒"))
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button(String(appLoc: "取消")) { dismiss() }
                }
                ToolbarItem(placement: .topBarTrailing) {
                    Button(String(appLoc: "保存")) { save() }
                        .fontWeight(.semibold)
                        .disabled(!canSave)
                }
            }
            .onAppear(perform: hydrate)
            .onChange(of: month) { _, newMonth in
                // 切月份后,把超出该月最大天数的「日」收回(避免「2月31日」这种永不触发的组合)。
                let maxD = Self.daysInMonth(newMonth)
                if dayOfMonth > maxD { dayOfMonth = maxD }
            }
            .alert(String(appLoc: "通知未开启"), isPresented: $showAuthDeniedAlert) {
                Button(String(appLoc: "好")) { dismiss() }
            } message: {
                Text("提醒已保存,但系统通知权限未开启,到点不会弹出。请在「设置 · 通知 · 康康」中允许。")
            }
            .alert(String(appLoc: "删除这条提醒?"), isPresented: $showDeleteConfirm) {
                Button(String(appLoc: "删除"), role: .destructive) { deleteReminder() }
                Button(String(appLoc: "取消"), role: .cancel) { }
            } message: {
                Text("删除后该提醒不再触发。")
            }
        }
    }

    // MARK: - 频率多选 chip

    private static let freqOrder: [CustomReminder.Frequency] = [.daily, .weekly, .monthly, .yearly]

    private func freqLabel(_ f: CustomReminder.Frequency) -> String {
        switch f {
        case .daily:   return String(appLoc: "每日")
        case .weekly:  return String(appLoc: "每周")
        case .monthly: return String(appLoc: "每月")
        case .yearly:  return String(appLoc: "每年")
        }
    }

    private var frequencyChips: some View {
        HStack(spacing: 8) {
            ForEach(Self.freqOrder, id: \.self) { f in
                let on = frequencies.contains(f)
                Button {
                    if on { frequencies.remove(f) } else { frequencies.insert(f) }
                } label: {
                    Text(freqLabel(f))
                        .font(.tjScaled( 13, weight: on ? .semibold : .regular))
                        .foregroundStyle(on ? Tj.Palette.paper : Tj.Palette.text)
                        .frame(maxWidth: .infinity, minHeight: 32)
                        .background(
                            RoundedRectangle(cornerRadius: 8, style: .continuous)
                                .fill(on ? Tj.Palette.ink : Tj.Palette.paper)
                        )
                        .overlay(
                            RoundedRectangle(cornerRadius: 8, style: .continuous)
                                .strokeBorder(Tj.Palette.line, lineWidth: on ? 0 : 1)
                        )
                }
                .buttonStyle(.plain)
            }
        }
        .listRowBackground(Color.clear)
    }

    // MARK: - 频率子控件(随勾选项展开,可同时出现多组)

    @ViewBuilder
    private var frequencyDetail: some View {
        if frequencies.contains(.weekly) {
            subCaption(String(appLoc: "每周 · 选星期几"))
            weekdayRow
        }
        if frequencies.contains(.monthly) {
            subCaption(String(appLoc: "每月 · 选日期(可多选)"))
            monthDayGrid
            if monthDays.contains(where: { $0 >= 29 }) { skipHint }
        }
        if frequencies.contains(.yearly) {
            subCaption(String(appLoc: "每年 · 选月/日"))
            Picker(String(appLoc: "月份"), selection: $month) {
                ForEach(1...12, id: \.self) { mo in
                    Text(String(appLoc: "\(mo)月")).tag(mo)
                }
            }
            Picker(String(appLoc: "日期"), selection: $dayOfMonth) {
                ForEach(1...Self.daysInMonth(month), id: \.self) { d in
                    Text(String(appLoc: "\(d)日")).tag(d)
                }
            }
            if month == 2 && dayOfMonth == 29 { skipHint }   // 仅闰年的 2/29
        }
    }

    private func subCaption(_ text: String) -> some View {
        Text(text)
            .font(.tjScaled( 11, weight: .semibold))
            .foregroundStyle(Tj.Palette.text3)
            .frame(maxWidth: .infinity, alignment: .leading)
            .listRowBackground(Color.clear)
    }

    /// 每月日期多选网格(1...31,7 列)。
    private var monthDayGrid: some View {
        LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 6), count: 7), spacing: 6) {
            ForEach(1...31, id: \.self) { d in
                let on = monthDays.contains(d)
                Button {
                    if on { monthDays.remove(d) } else { monthDays.insert(d) }
                } label: {
                    Text("\(d)")
                        .font(.tjScaled( 12, weight: on ? .semibold : .regular))
                        .foregroundStyle(on ? Tj.Palette.paper : Tj.Palette.text)
                        .frame(maxWidth: .infinity, minHeight: 30)
                        .background(
                            RoundedRectangle(cornerRadius: 6, style: .continuous)
                                .fill(on ? Tj.Palette.ink : Tj.Palette.paper)
                        )
                        .overlay(
                            RoundedRectangle(cornerRadius: 6, style: .continuous)
                                .strokeBorder(Tj.Palette.line, lineWidth: on ? 0 : 1)
                        )
                }
                .buttonStyle(.plain)
            }
        }
        .listRowBackground(Color.clear)
    }

    private var skipHint: some View {
        Text(String(appLoc: "部分月份无此日,该月将跳过"))
            .font(.tjScaled( 11))
            .foregroundStyle(Tj.Palette.text3)
    }

    /// 某月最大天数(2 月取 29,允许设闰年 2/29)。
    private static func daysInMonth(_ month: Int) -> Int {
        switch month {
        case 2:           return 29
        case 4, 6, 9, 11: return 30
        default:          return 31
        }
    }

    // MARK: - 时间快捷预设

    private var timePresetRow: some View {
        let cal = Calendar.current
        let curH = cal.component(.hour, from: pickedTime)
        let curM = cal.component(.minute, from: pickedTime)
        return HStack(spacing: 8) {
            ForEach(Array(timePresets.enumerated()), id: \.offset) { _, preset in
                let on = curH == preset.h && curM == preset.m
                Button {
                    pickedTime = cal.date(bySettingHour: preset.h, minute: preset.m,
                                          second: 0, of: pickedTime) ?? pickedTime
                } label: {
                    Text(String(format: "%d:%02d", preset.h, preset.m))
                        .font(.tjScaled( 13, weight: on ? .semibold : .regular))
                        .foregroundStyle(on ? Tj.Palette.paper : Tj.Palette.text)
                        .frame(maxWidth: .infinity, minHeight: 30)
                        .background(
                            RoundedRectangle(cornerRadius: 8, style: .continuous)
                                .fill(on ? Tj.Palette.ink : Tj.Palette.paper)
                        )
                        .overlay(
                            RoundedRectangle(cornerRadius: 8, style: .continuous)
                                .strokeBorder(Tj.Palette.line, lineWidth: on ? 0 : 1)
                        )
                }
                .buttonStyle(.plain)
            }
        }
        .listRowBackground(Color.clear)
    }

    // MARK: - 周几选择(与 RemindersListView 同款)

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

    // MARK: - 数据

    private func hydrate() {
        guard !hydrated else { return }
        hydrated = true
        if let r = reminder {
            title = r.title
            note = r.note
            frequencies = r.frequencies
            weekdays = Set(r.weekdays)
            monthDays = Set(r.monthlyDays)
            dayOfMonth = r.dayOfMonth
            month = r.month
            pickedTime = Calendar.current.date(
                bySettingHour: r.hour, minute: r.minute, second: 0, of: .now
            ) ?? .now
        } else {
            // 新建模式:从调用方带进来的预填(药名 / 用法)。
            title = prefillTitle
            note = prefillNote
        }
    }

    private func save() {
        guard canSave else { return }
        let cal = Calendar.current
        let hour = cal.component(.hour, from: pickedTime)
        let minute = cal.component(.minute, from: pickedTime)
        let sortedDays = weekdays.sorted()
        let sortedMonthDays = monthDays.sorted()

        let target: CustomReminder
        if let r = reminder {
            r.title = trimmedTitle
            r.note = note.trimmingCharacters(in: .whitespacesAndNewlines)
            r.hour = hour
            r.minute = minute
            r.weekdays = sortedDays
            r.frequencies = frequencies        // 写 frequenciesRaw(+ 代表 frequencyRaw)
            r.monthlyDays = sortedMonthDays     // 写 monthDays
            r.dayOfMonth = dayOfMonth           // 仅每年用
            r.month = month
            r.updatedAt = .now
            target = r
        } else {
            let new = CustomReminder(
                title: trimmedTitle,
                note: note.trimmingCharacters(in: .whitespacesAndNewlines),
                hour: hour,
                minute: minute,
                weekdays: sortedDays,
                dayOfMonth: dayOfMonth,
                month: month
            )
            new.frequencies = frequencies
            new.monthlyDays = sortedMonthDays
            ctx.insert(new)
            target = new
        }
        try? ctx.save()

        Task { @MainActor in
            let state = await ReminderService.requestAuthorization()
            await ReminderService.sync(target)
            if state == .denied {
                showAuthDeniedAlert = true
            } else {
                dismiss()
            }
        }
    }

    private func deleteReminder() {
        guard let r = reminder else { return }
        ReminderService.cancel(customId: r.id)
        ctx.delete(r)
        try? ctx.save()
        dismiss()
    }
}

#Preview("新建") {
    CustomReminderEditSheet()
        .modelContainer(for: [CustomReminder.self], inMemory: true)
}
