import Foundation
import SwiftUI

struct EditTempTargetForm: View {
    @ObservedObject var tempTarget: TempTargetStored
    @Environment(\.presentationMode) var presentationMode
    @Environment(\.colorScheme) var colorScheme
    @Environment(AppState.self) var appState
    @StateObject var state: Adjustments.StateModel
    @State private var displayPickerDuration: Bool = false
    @State private var displayPickerTarget: Bool = false
    @State private var tempTargetSensitivityAdjustmentType: TempTargetSensitivityAdjustmentType = .standard
    @State private var durationHours = 0
    @State private var durationMinutes = 0
    @State private var targetStep: Decimal = 1
    @State private var name: String
    @State private var target: Decimal
    @State private var duration: Decimal
    @State private var date: Date
    @State private var halfBasalTarget: Decimal?
    @State private var percentage: Double

    @State private var hasChanges = false
    @State private var showAlert = false
    @State private var isUsingSlider = false
    @State private var isPreset = false
    @State private var isEnabled = false

    init(tempTargetToEdit: TempTargetStored, state: Adjustments.StateModel) {
        tempTarget = tempTargetToEdit
        _state = StateObject(wrappedValue: state)
        _name = State(initialValue: tempTargetToEdit.name ?? "")
        _target = State(initialValue: tempTargetToEdit.target?.decimalValue ?? 0)
        _duration = State(initialValue: tempTargetToEdit.duration?.decimalValue ?? 0)
        _date = State(initialValue: tempTargetToEdit.date ?? Date())
        _halfBasalTarget = State(initialValue: tempTargetToEdit.halfBasalTarget?.decimalValue ?? state.settingHalfBasalTarget)
        _isPreset = State(initialValue: tempTargetToEdit.isPreset)
        _isEnabled = State(initialValue: tempTargetToEdit.enabled)

        let tempTargetHalfBasal: Decimal = (tempTargetToEdit.halfBasalTarget?.decimalValue) ?? state.settingHalfBasalTarget

        let H = tempTargetHalfBasal
        let T = tempTargetToEdit.target?.decimalValue ?? 100
        let calcPercentage = TempTargetCalculations.computeAdjustedPercentage(
            halfBasalTarget: H,
            target: T,
            autosensMax: state.autosensMax
        )
        _percentage = State(initialValue: calcPercentage)
    }

    private var dateFormatter: DateFormatter {
        let f = DateFormatter()
        f.dateStyle = .short
        f.timeStyle = .short
        return f
    }

    var body: some View {
        NavigationView {
            List {
                editTempTarget()
                saveButton
            }
            .listSectionSpacing(10)
            .padding(.top, 30)
            .ignoresSafeArea(edges: .top)
            .scrollContentBackground(.hidden)
            .background(appState.trioBackgroundColor(for: colorScheme))
            .navigationTitle("Edit Temp Target")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button(action: {
                        presentationMode.wrappedValue.dismiss()
                    }, label: {
                        Text("Cancel")
                    })
                }
                ToolbarItem(placement: .topBarTrailing) {
                    Button(
                        action: {
                            state.isHelpSheetPresented.toggle()
                        },
                        label: {
                            Image(systemName: "questionmark.circle")
                        }
                    )
                }
            }
            .onAppear {
                // Determine if this is a custom slider adjustment or a standard with auto-adjustment
                if halfBasalTarget != nil,
                   halfBasalTarget != state.settingHalfBasalTarget
                {
                    // Check if this was an auto-adjusted standard TT:
                    // If computeEffectiveHBT with nil stored HBT returns non-nil, settings HBT would produce <= 15%
                    let isAutoAdjustedStandard = TempTargetCalculations.computeEffectiveHBT(
                        tempTargetHalfBasalTarget: nil,
                        settingHalfBasalTarget: state.settingHalfBasalTarget,
                        target: target,
                        autosensMax: state.autosensMax
                    ) != nil

                    if !isAutoAdjustedStandard {
                        tempTargetSensitivityAdjustmentType = .slider
                    }
                }
            }
            .sheet(isPresented: $state.isHelpSheetPresented) {
                TempTargetHelpView(state: state, helpSheetDetent: $state.helpSheetDetent)
            }
        }
    }

    private func calculatedEndDate(from startDate: Date, totalDuration: Decimal) -> Date {
        let elapsedTime = Date().timeIntervalSince(startDate)
        let totalDurationSeconds = Int(totalDuration) * 60
        let remainingTime = max(totalDurationSeconds - Int(elapsedTime), 0)
        return Date().addingTimeInterval(TimeInterval(remainingTime))
    }

    private func formattedEndTime(startDate: Date, totalDuration: Decimal) -> String {
        let endDate = calculatedEndDate(from: startDate, totalDuration: totalDuration)
        let formatter = DateFormatter()

        if Calendar.current.isDateInToday(endDate) {
            formatter.dateStyle = .none
            formatter.timeStyle = .short // show only the time
        } else {
            formatter.dateStyle = .short
            formatter.timeStyle = .short // show Date and time
        }

        return formatter.string(from: endDate)
    }

    @ViewBuilder private func editTempTarget() -> some View {
        Group {
            Section {
                HStack {
                    Text("Name")
                    Spacer()
                    TextField("(Optional)", text: $name)
                        .multilineTextAlignment(.trailing)
                        .onChange(of: name) {
                            hasChanges = true
                        }
                }
            }.listRowBackground(Color.chart)

            Section {
                // Picker on the right side
                let settingsProvider = PickerSettingsProvider.shared
                let glucoseSetting = PickerSetting(value: 0, step: targetStep, min: 80, max: 200, type: .glucose)
                TargetPicker(
                    label: "Target Glucose",
                    selection: Binding(
                        get: { target },
                        set: { target = $0 }
                    ),
                    options: settingsProvider.generatePickerValues(
                        from: glucoseSetting,
                        units: state.units,
                        roundMinToStep: true
                    ),
                    units: state.units,
                    hasChanges: $hasChanges,
                    targetStep: $targetStep,
                    displayPickerTarget: $displayPickerTarget,
                    toggleScrollWheel: toggleScrollWheel
                )
                .onChange(of: target) {
                    // percentage = state.computeAdjustedPercentage(usingHBT: halfBasalTarget, usingTarget: target)
                    // target value changes shall not alter the sensitivity, instead calculate new hbt with sensitivity from slider
                    halfBasalTarget = Decimal(
                        TempTargetCalculations
                            .computeHalfBasalTarget(target: target, percentage: percentage)
                    )
                }
            }
            .listRowBackground(Color.chart)

            if target != TempTargetCalculations.normalTarget {
                let computedHalfBasalTarget = Decimal(
                    TempTargetCalculations.computeHalfBasalTarget(target: target, percentage: percentage)
                )

                if state.isAdjustSensEnabled(usingTarget: target) {
                    Section(
                        footer: state.percentageDescription(percentage),
                        content: {
                            Picker("Sensitivity Adjustment", selection: $tempTargetSensitivityAdjustmentType) {
                                ForEach(TempTargetSensitivityAdjustmentType.allCases, id: \.self) { option in
                                    Text(option.rawValue).tag(option)
                                }
                                .pickerStyle(MenuPickerStyle())
                                .onChange(of: tempTargetSensitivityAdjustmentType) { _, newValue in
                                    if newValue == .standard {
                                        halfBasalTarget = nil
                                        hasChanges = true
                                        percentage = TempTargetCalculations.computeAdjustedPercentage(
                                            halfBasalTarget: state.settingHalfBasalTarget,
                                            target: target,
                                            autosensMax: state.autosensMax
                                        )
                                    }
                                }
                            }

                            Text("\(formattedPercentage(percentage))% Insulin")
                                .foregroundColor(isUsingSlider ? .orange : Color.tabBar)
                                .font(.title3)
                                .fontWeight(.bold)
                                .frame(maxWidth: .infinity, alignment: .center)

                            if tempTargetSensitivityAdjustmentType == .slider {
                                Slider(
                                    value: Binding(
                                        get: {
                                            Double(truncating: percentage as NSNumber)
                                        },
                                        set: { newValue in
                                            percentage = newValue
                                            hasChanges = true
                                            halfBasalTarget = Decimal(TempTargetCalculations.computeHalfBasalTarget(
                                                target: target,
                                                percentage: percentage
                                            ))
                                        }
                                    ),
                                    in: state.computeSliderLow(usingTarget: target) ... state
                                        .computeSliderHigh(usingTarget: target),
                                    step: 5
                                ) {}
                                minimumValueLabel: {
                                    Text("\(state.computeSliderLow(usingTarget: target), specifier: "%.0f")%")
                                }
                                maximumValueLabel: {
                                    Text("\(state.computeSliderHigh(usingTarget: target), specifier: "%.0f")%")
                                }
                                .listRowSeparator(.hidden, edges: .top)
                            }
                        }
                    )
                    .listRowBackground(Color.chart)
                }
            }

            Section {
                DatePicker("Start Time", selection: $date, in: Date.now...)
                    .onChange(of: date) { hasChanges = true }
            }.listRowBackground(Color.chart)

            Section {
                VStack {
                    HStack {
                        Text("Duration")
                        Spacer()
                        Text(state.formatHoursAndMinutes(Int(duration)))
                            .foregroundColor(!displayPickerDuration ? (duration > 0 ? .primary : .secondary) : .accentColor)
                            .onTapGesture {
                                displayPickerDuration = toggleScrollWheel(displayPickerDuration)
                            }
                    }

                    if displayPickerDuration {
                        HStack {
                            Picker(
                                selection: Binding(
                                    get: {
                                        Int(truncating: duration as NSNumber) / 60
                                    },
                                    set: {
                                        let minutes = Int(truncating: duration as NSNumber) % 60
                                        let totalMinutes = $0 * 60 + minutes
                                        duration = Decimal(totalMinutes)
                                        hasChanges = duration > 0 ? true : false // prevents the user from setting 0 min
                                    }
                                ),
                                label: Text("")
                            ) {
                                ForEach(0 ..< 24) { hour in
                                    Text("\(hour) hr").tag(hour)
                                }
                            }
                            .pickerStyle(WheelPickerStyle())
                            .frame(maxWidth: .infinity)

                            Picker(
                                selection: Binding(
                                    get: {
                                        Int(truncating: duration as NSNumber) %
                                            60 // Convert Decimal to Int for modulus operation
                                    },
                                    set: {
                                        duration = Decimal((Int(truncating: duration as NSNumber) / 60) * 60 + $0)
                                        hasChanges = duration > 0 ? true : false
                                    }
                                ),
                                label: Text("")
                            ) {
                                ForEach(Array(stride(from: 0, through: 55, by: 5)), id: \.self) { minute in
                                    Text("\(minute) min").tag(minute)
                                }
                            }
                            .pickerStyle(WheelPickerStyle())
                            .frame(maxWidth: .infinity)
                        }
                        .listRowSeparator(.hidden, edges: .top)
                    }
                }
            }.listRowBackground(Color.chart)

            if isEnabled {
                Section {
                    HStack {
                        Spacer()
                        Text("Until \(formattedEndTime(startDate: date, totalDuration: duration))").foregroundStyle(.secondary)
                    }
                }.listRowBackground(Color.clear)
            }
        }
    }

    private var saveButton: some View {
        HStack {
            Spacer()
            Button(action: {
                saveChanges()
                debug(
                    .default,
                    "TempTarget: target=\(target), HBT=\(state.settingHalfBasalTarget), effectiveHBT=\(String(describing: halfBasalTarget)), percentage=\(Int(percentage))%, adjustmentType=\(tempTargetSensitivityAdjustmentType.rawValue)"
                )
                do {
                    guard let moc = tempTarget.managedObjectContext else { return }
                    guard moc.hasChanges else { return }
                    try moc.save()

                    if let currentActiveTempTarget = state.currentActiveTempTarget {
                        Task {
                            // TODO: - Creating a Run entry is probably needed for Overrides as well and the reason for "jumping" Overrides?
                            // Disable previous active Temp Targets
                            await state.disableAllActiveTempTargets(
                                except: currentActiveTempTarget.objectID,
                                createTempTargetRunEntry: false
                            )

                            // If the temp target which currently gets edited is enabled, then store it to the Temp Target JSON so that oref uses it
                            if isEnabled {
                                let tempTarget = TempTarget(
                                    name: name,
                                    createdAt: Date(),
                                    targetTop: target,
                                    targetBottom: target,
                                    duration: duration,
                                    enteredBy: TempTarget.local,
                                    reason: TempTarget.custom,
                                    isPreset: isPreset ? true : false,
                                    enabled: isEnabled ? true : false,
                                    halfBasalTarget: halfBasalTarget
                                )

                                // Store to TempTargetStorage so that oref uses the edited Temp target
                                state.saveTempTargetToStorage(tempTargets: [tempTarget])
                            }

                            // Update view
                            state.updateLatestTempTargetConfiguration()
                        }
                    }
                    hasChanges = false
                    presentationMode.wrappedValue.dismiss()
                } catch {
                    debugPrint("Failed to Edit Temp Target")
                }
            }, label: {
                Text("Save")
            })
                .disabled(!hasChanges)
                .frame(maxWidth: .infinity, alignment: .center)
                .tint(.white)

            Spacer()
        }.listRowBackground(hasChanges ? Color(.systemBlue) : Color(.systemGray4))
    }

    private func saveChanges() {
        tempTarget.name = name
        tempTarget.target = NSDecimalNumber(decimal: target)
        tempTarget.duration = NSDecimalNumber(decimal: duration)
        tempTarget.date = date
        tempTarget.isUploadedToNS = false
        if let halfBasalValue = halfBasalTarget {
            tempTarget.halfBasalTarget = NSDecimalNumber(decimal: halfBasalValue)
        } else {
            tempTarget.halfBasalTarget = nil
        }
    }

    private func toggleScrollWheel(_ toggle: Bool) -> Bool {
        displayPickerDuration = false
        displayPickerTarget = false
        return !toggle
    }

    private func resetValues() {
        name = tempTarget.name ?? ""
        target = tempTarget.target?.decimalValue ?? 0
        duration = tempTarget.duration?.decimalValue ?? 0
        date = tempTarget.date ?? Date()
    }

    private func totalDurationInMinutes() -> Int {
        let durationTotal = (durationHours * 60) + durationMinutes
        return max(0, durationTotal)
    }

    private var formatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.maximumFractionDigits = 0
        return formatter
    }

    private var glucoseFormatter: NumberFormatter {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        if state.units == .mmolL {
            formatter.maximumFractionDigits = 1
        } else {
            formatter.maximumFractionDigits = 0
        }
        formatter.roundingMode = .halfUp
        return formatter
    }

    private func formattedPercentage(_ value: Double) -> String {
        let percentageNumber = NSNumber(value: value)
        return formatter.string(from: percentageNumber) ?? "\(value)"
    }

    private func formattedGlucose(glucose: Decimal) -> String {
        let formattedValue: String
        if state.units == .mgdL {
            formattedValue = glucoseFormatter.string(from: glucose as NSDecimalNumber) ?? "\(glucose)"
        } else {
            formattedValue = glucose.formattedAsMmolL
        }
        return "\(formattedValue) \(state.units.rawValue)"
    }
}
