//
//  InsulinSensitivityScheduleEditor.swift
//  LoopKitUI
//
//  Created by Michael Pangburn on 4/20/20.
//  Copyright © 2020 LoopKit Authors. All rights reserved.
//

import SwiftUI
import HealthKit
import LoopKit


public struct InsulinSensitivityScheduleEditor: View {
    @EnvironmentObject private var displayGlucoseUnitObservable: DisplayGlucoseUnitObservable
    @Environment(\.appName) private var appName

    let mode: SettingsPresentationMode
    let viewModel: InsulinSensitivityScheduleEditorViewModel

    var displayGlucoseUnit: HKUnit {
        displayGlucoseUnitObservable.displayGlucoseUnit
    }

    public init(
        mode: SettingsPresentationMode,
        therapySettingsViewModel: TherapySettingsViewModel,
        didSave: (() -> Void)? = nil
    ) {
        self.mode = mode
        self.viewModel = InsulinSensitivityScheduleEditorViewModel(
            therapySettingsViewModel: therapySettingsViewModel,
            didSave: didSave)
    }

    public var body: some View {
        QuantityScheduleEditor(
            title: Text(TherapySetting.insulinSensitivity.title),
            description: description,
            schedule: viewModel.insulinSensitivitySchedule?.schedule(for: displayGlucoseUnit),
            unit: sensitivityUnit,
            guardrail: .insulinSensitivity,
            selectableValueStride: stride,
            defaultFirstScheduleItemValue: Guardrail.insulinSensitivity.startingSuggestion ?? Guardrail.insulinSensitivity.recommendedBounds.upperBound,
            confirmationAlertContent: confirmationAlertContent,
            guardrailWarning: InsulinSensitivityGuardrailWarning.init(crossedThresholds:),
            onSave: { insulinSensitivitySchedulePerU in
                // the sensitivity units are passed as the units to display `/U`
                // need to go back to displayGlucoseUnit. This does not affect the value
                // force unwrapping since dailyItems are already validated
                let insulinSensitivitySchedule = InsulinSensitivitySchedule(unit: displayGlucoseUnit,
                                                                            dailyItems: insulinSensitivitySchedulePerU.items,
                                                                            timeZone: insulinSensitivitySchedulePerU.timeZone)!
                viewModel.saveInsulinSensitivitySchedule(insulinSensitivitySchedule)
            },
            mode: mode,
            settingType: .insulinSensitivity
        )
    }

    private var description: Text {
        Text(TherapySetting.insulinSensitivity.descriptiveText(appName: appName))
    }

    private var sensitivityUnit: HKUnit {
        displayGlucoseUnit.unitDivided(by: .internationalUnit())
    }

    private var stride: HKQuantity {
        let doubleValue: Double
        switch displayGlucoseUnit {
        case .milligramsPerDeciliter:
            doubleValue = 1
        case .millimolesPerLiter:
            doubleValue = 0.1
        case let otherUnit:
            fatalError("Unsupported glucose unit \(otherUnit)")
        }

        return HKQuantity(unit: sensitivityUnit, doubleValue: doubleValue)
    }

    private var confirmationAlertContent: AlertContent {
        AlertContent(
            title: Text(LocalizedString("Save Insulin Sensitivities?", comment: "Alert title for confirming insulin sensitivities outside the recommended range")),
            message: Text(TherapySetting.insulinSensitivity.guardrailSaveWarningCaption)
        )
    }
}

private struct InsulinSensitivityGuardrailWarning: View {
    var crossedThresholds: [SafetyClassification.Threshold]

    var body: some View {
        assert(!crossedThresholds.isEmpty)
        return GuardrailWarning(
            therapySetting: .insulinSensitivity,
            title: crossedThresholds.count == 1 ? singularWarningTitle(for: crossedThresholds.first!) : multipleWarningTitle,
            thresholds: crossedThresholds
        )
    }

    private func singularWarningTitle(for threshold: SafetyClassification.Threshold) -> Text {
        switch threshold {
        case .minimum, .belowRecommended:
            return Text(LocalizedString("Low Insulin Sensitivity", comment: "Title text for the low insulin sensitivity warning"))
        case .aboveRecommended, .maximum:
            return Text(LocalizedString("High Insulin Sensitivity", comment: "Title text for the high insulin sensitivity warning"))
        }
    }

    private var multipleWarningTitle: Text {
        Text(LocalizedString("Insulin Sensitivities", comment: "Title text for multi-value insulin sensitivity warning"))
    }
}
