//
//  MockPumpManagerSettingsViewController.swift
//  LoopKitUI
//
//  Created by Michael Pangburn on 11/20/18.
//  Copyright © 2018 LoopKit Authors. All rights reserved.
//

import UIKit
import HealthKit
import LoopKit
import LoopKitUI
import MockKit
import SwiftUI


final class MockPumpManagerSettingsViewController: UITableViewController {

    let pumpManager: MockPumpManager
    let supportedInsulinTypes: [InsulinType]

    init(pumpManager: MockPumpManager, supportedInsulinTypes: [InsulinType]) {
        self.pumpManager = pumpManager
        self.supportedInsulinTypes = supportedInsulinTypes
        super.init(style: .grouped)
        title = LocalizedString("Pump Settings", comment: "Title for Pump simulator settings")
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private let quantityFormatter = QuantityFormatter()

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.rowHeight = UITableView.automaticDimension
        tableView.estimatedRowHeight = 44

        tableView.sectionHeaderHeight = UITableView.automaticDimension
        tableView.estimatedSectionHeaderHeight = 55

        tableView.register(DateAndDurationTableViewCell.nib(), forCellReuseIdentifier: DateAndDurationTableViewCell.className)
        tableView.register(SegmentedControlTableViewCell.self, forCellReuseIdentifier: SegmentedControlTableViewCell.className)
        tableView.register(SettingsTableViewCell.self, forCellReuseIdentifier: SettingsTableViewCell.className)
        tableView.register(BoundSwitchTableViewCell.self, forCellReuseIdentifier: BoundSwitchTableViewCell.className)
        tableView.register(TextButtonTableViewCell.self, forCellReuseIdentifier: TextButtonTableViewCell.className)
        tableView.register(SuspendResumeTableViewCell.self, forCellReuseIdentifier: SuspendResumeTableViewCell.className)

        pumpManager.addStatusObserver(self, queue: .main)

        let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:)))
        self.navigationItem.setRightBarButton(button, animated: false)
    }

    @objc func doneTapped(_ sender: Any) {
        done()
    }

    private func done() {
        if let nav = navigationController as? SettingsNavigationViewController {
            nav.notifyComplete()
        }
    }

    // MARK: - Data Source

    private enum Section: Int, CaseIterable {
        case basalRate = 0
        case actions
        case settings
        case statusProgress
        case deletePump
    }

    private enum ActionRow: Int, CaseIterable {
        case suspendResume = 0
        case occlusion
        case pumpError
    }

    private enum SettingsRow: Int, CaseIterable {
        case deliverableIncrements = 0
        case supportedBasalRates
        case supportedBolusVolumes
        case insulinType
        case reservoirRemaining
        case batteryRemaining
        case tempBasalErrorToggle
        case bolusErrorToggle
        case bolusCancelErrorToggle
        case suspendErrorToggle
        case resumeErrorToggle
        case uncertainDeliveryErrorToggle
        case lastReconciliationDate
    }
    
    private enum StatusProgressRow: Int, CaseIterable {
        case percentComplete
        case warningThreshold
        case criticalThreshold
    }

    // MARK: UITableViewDataSource

    override func numberOfSections(in tableView: UITableView) -> Int {
        return Section.allCases.count
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch Section(rawValue: section)! {
        case .basalRate:
            return 1
        case .actions:
            return ActionRow.allCases.count
        case .settings:
            return SettingsRow.allCases.count
        case .statusProgress:
            return StatusProgressRow.allCases.count
        case .deletePump:
            return 1
        }
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        switch Section(rawValue: section)! {
        case .basalRate:
            return nil
        case .actions:
            return nil
        case .settings:
            return "Configuration"
        case .statusProgress:
            return "Status Progress"
        case .deletePump:
            return " "  // Use an empty string for more dramatic spacing
        }
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch Section(rawValue: indexPath.section)! {
        case .basalRate:
            let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath)
            cell.textLabel?.text = "Current Basal Rate"
            if let currentBasalRate = pumpManager.currentBasalRate {
                cell.detailTextLabel?.text = quantityFormatter.string(from: currentBasalRate, for: HKUnit.internationalUnit().unitDivided(by: .hour()))
            } else {
                cell.detailTextLabel?.text = "—"
            }
            cell.isUserInteractionEnabled = false
            return cell
        case .actions:
            switch ActionRow(rawValue: indexPath.row)! {
            case .suspendResume:
                let cell = tableView.dequeueReusableCell(withIdentifier: SuspendResumeTableViewCell.className, for: indexPath) as! SuspendResumeTableViewCell
                cell.basalDeliveryState = pumpManager.status.basalDeliveryState
                return cell
            case .occlusion:
                let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell
                if pumpManager.state.occlusionDetected {
                    cell.textLabel?.text = "Resolve Occlusion"
                } else {
                    cell.textLabel?.text = "Detect Occlusion"
                }
                return cell
            case .pumpError:
                let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell
                if pumpManager.state.pumpErrorDetected {
                    cell.textLabel?.text = "Resolve Pump Error"
                } else {
                    cell.textLabel?.text = "Cause Pump Error"
                }
                return cell
            }
        case .settings:
            switch SettingsRow(rawValue: indexPath.row)! {
            case .deliverableIncrements:
                let cell = tableView.dequeueReusableCell(withIdentifier: SegmentedControlTableViewCell.className, for: indexPath) as! SegmentedControlTableViewCell
                let possibleDeliverableIncrements = MockPumpManagerState.DeliverableIncrements.allCases
                cell.textLabel?.text = "Increments"
                cell.options = possibleDeliverableIncrements.map { increments in
                    switch increments {
                    case .omnipod:
                        return "Pod"
                    case .medtronicX22:
                        return "x22"
                    case .medtronicX23:
                        return "x23"
                    case .custom:
                        return "Custom"
                    }
                }
                cell.segmentedControl.selectedSegmentIndex = possibleDeliverableIncrements.firstIndex(of: pumpManager.state.deliverableIncrements)!
                cell.onSelection { [pumpManager] index in
                    pumpManager.state.deliverableIncrements = possibleDeliverableIncrements[index]
                    tableView.reloadRows(at: [IndexPath(row: SettingsRow.supportedBasalRates.rawValue, section: Section.settings.rawValue), IndexPath(row: SettingsRow.supportedBolusVolumes.rawValue, section: Section.settings.rawValue)], with: .automatic)
                }
                return cell
            case .supportedBasalRates:
                let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath)
                cell.textLabel?.text = "Basal Rates"
                cell.detailTextLabel?.text = pumpManager.state.supportedBasalRatesDescription
                if pumpManager.state.deliverableIncrements == .custom {
                    cell.accessoryType = .disclosureIndicator
                }
                return cell
            case .supportedBolusVolumes:
                let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath)
                cell.textLabel?.text = "Bolus Volumes"
                cell.detailTextLabel?.text = pumpManager.state.supportedBolusVolumesDescription
                if pumpManager.state.deliverableIncrements == .custom {
                    cell.accessoryType = .disclosureIndicator
                }
                return cell
            case .insulinType:
                let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath)
                cell.prepareForReuse()
                cell.textLabel?.text = "Insulin Type"
                cell.detailTextLabel?.text = pumpManager.state.insulinType?.brandName ?? "Unset"
                cell.accessoryType = .disclosureIndicator
                return cell
            case .reservoirRemaining:
                let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath)
                cell.textLabel?.text = "Reservoir Remaining"
                cell.detailTextLabel?.text = quantityFormatter.string(from: HKQuantity(unit: .internationalUnit(), doubleValue: pumpManager.state.reservoirUnitsRemaining), for: .internationalUnit())
                cell.accessoryType = .disclosureIndicator
                return cell
            case .batteryRemaining:
                let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath)
                cell.textLabel?.text = "Battery Remaining"
                if let remainingCharge = pumpManager.status.pumpBatteryChargeRemaining {
                    cell.detailTextLabel?.text = "\(Int(round(remainingCharge * 100)))%"
                } else {
                    cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString
                }
                cell.accessoryType = .disclosureIndicator
                return cell
            case .tempBasalErrorToggle:
                return switchTableViewCell(for: indexPath, titled: "Error on Temp Basal", boundTo: \.tempBasalEnactmentShouldError)
            case .bolusErrorToggle:
                return switchTableViewCell(for: indexPath, titled: "Error on Bolus", boundTo: \.bolusEnactmentShouldError)
            case .bolusCancelErrorToggle:
                return switchTableViewCell(for: indexPath, titled: "Error on Cancel Bolus", boundTo: \.bolusCancelShouldError)
            case .suspendErrorToggle:
                return switchTableViewCell(for: indexPath, titled: "Error on Suspend", boundTo: \.deliverySuspensionShouldError)
            case .resumeErrorToggle:
                return switchTableViewCell(for: indexPath, titled: "Error on Resume", boundTo: \.deliveryResumptionShouldError)
            case .uncertainDeliveryErrorToggle:
                return switchTableViewCell(for: indexPath, titled: "Next Delivery Command Uncertain", boundTo: \.deliveryCommandsShouldTriggerUncertainDelivery)
            case .lastReconciliationDate:
                let cell = tableView.dequeueReusableCell(withIdentifier: DateAndDurationTableViewCell.className, for: indexPath) as! DateAndDurationTableViewCell
                cell.titleLabel.text = "Last Reconciliation Date"
                cell.date = pumpManager.lastSync ?? Date()
                cell.datePicker.maximumDate = Date()
                cell.datePicker.minimumDate = Date() - .hours(48)
                cell.datePicker.datePickerMode = .dateAndTime
                #if swift(>=5.2)
                    if #available(iOS 14.0, *) {
                        cell.datePicker.preferredDatePickerStyle = .wheels
                    }
                #endif
                cell.datePicker.isEnabled = true
                cell.delegate = self
                return cell
            }
        case .statusProgress:
            let cell = tableView.dequeueReusableCell(withIdentifier: SettingsTableViewCell.className, for: indexPath)
            switch StatusProgressRow(rawValue: indexPath.row)! {
            case .percentComplete:
                cell.textLabel?.text = "Percent Completed"
                if let percentCompleted = pumpManager.state.progressPercentComplete {
                    cell.detailTextLabel?.text = "\(Int(round(percentCompleted * 100)))%"
                } else {
                    cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString
                }
            case .warningThreshold:
                cell.textLabel?.text = "Warning Threshold"
                if let warningThreshold = pumpManager.state.progressWarningThresholdPercentValue {
                    cell.detailTextLabel?.text = "\(Int(round(warningThreshold * 100)))%"
                } else {
                    cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString
                }
            case .criticalThreshold:
                cell.textLabel?.text = "Critical Threshold"
                if let criticalThreshold = pumpManager.state.progressCriticalThresholdPercentValue {
                    cell.detailTextLabel?.text = "\(Int(round(criticalThreshold * 100)))%"
                } else {
                    cell.detailTextLabel?.text = SettingsTableViewCell.NoValueString
                }
            }
            cell.accessoryType = .disclosureIndicator
            return cell
        case .deletePump:
            let cell = tableView.dequeueReusableCell(withIdentifier: TextButtonTableViewCell.className, for: indexPath) as! TextButtonTableViewCell
            cell.textLabel?.text = "Delete Pump"
            cell.textLabel?.textAlignment = .center
            cell.tintColor = .delete
            cell.isEnabled = true
            return cell
        }
    }

    private func switchTableViewCell(for indexPath: IndexPath, titled title: String, boundTo keyPath: WritableKeyPath<MockPumpManagerState, Bool>) -> SwitchTableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: BoundSwitchTableViewCell.className, for: indexPath) as! BoundSwitchTableViewCell
        cell.textLabel?.text = title
        cell.switch?.isOn = pumpManager.state[keyPath: keyPath]
        cell.onToggle = { [unowned pumpManager] isOn in
            pumpManager.state[keyPath: keyPath] = isOn
        }
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let sender = tableView.cellForRow(at: indexPath)

        switch Section(rawValue: indexPath.section)! {
        case .actions:
            switch ActionRow(rawValue: indexPath.row)! {
            case .suspendResume:
                if let suspendResumeCell = sender as? SuspendResumeTableViewCell {
                    suspendResumeCellTapped(suspendResumeCell)
                }
                tableView.deselectRow(at: indexPath, animated: true)
            case .occlusion:
                pumpManager.injectPumpEvents(pumpManager.state.occlusionDetected ? [NewPumpEvent(alarmClearAt: Date())] : [NewPumpEvent(alarmAt: Date(), alarmType: .occlusion)])
                pumpManager.state.occlusionDetected = !pumpManager.state.occlusionDetected
                tableView.deselectRow(at: indexPath, animated: true)
                tableView.reloadRows(at: [indexPath], with: .automatic)
            case .pumpError:
                pumpManager.injectPumpEvents(pumpManager.state.pumpErrorDetected ? [NewPumpEvent(alarmClearAt: Date())] : [NewPumpEvent(alarmAt: Date(), alarmType: .other("Mock Pump Error"))])
                pumpManager.state.pumpErrorDetected = !pumpManager.state.pumpErrorDetected
                tableView.deselectRow(at: indexPath, animated: true)
                tableView.reloadRows(at: [indexPath], with: .automatic)
            }
        case .settings:
            tableView.deselectRow(at: indexPath, animated: true)
            switch SettingsRow(rawValue: indexPath.row)! {
            case .deliverableIncrements:
                break
            case .supportedBasalRates:
                if pumpManager.state.deliverableIncrements == .custom, pumpManager.state.supportedBasalRates.indices.contains(1) {
                    let basalRates = pumpManager.state.supportedBasalRates
                    let vc = SupportedRangeTableViewController(minValue: basalRates.first!, maxValue: basalRates.last!, stepSize: basalRates[1] - basalRates.first!)
                    vc.title = "Supported Basal Rates"
                    vc.indexPath = indexPath
                    vc.delegate = self
                    show(vc, sender: sender)
                }
                break
            case .supportedBolusVolumes:
                if pumpManager.state.deliverableIncrements == .custom, pumpManager.state.supportedBolusVolumes.indices.contains(1) {
                    let bolusVolumes = pumpManager.state.supportedBolusVolumes
                    let vc = SupportedRangeTableViewController(minValue: bolusVolumes.first!, maxValue: bolusVolumes.last!, stepSize: bolusVolumes[1] - bolusVolumes.first!)
                    vc.title = "Supported Bolus Volumes"
                    vc.indexPath = indexPath
                    vc.delegate = self
                    show(vc, sender: sender)
                }
                break
            case .insulinType:
                let view = InsulinTypeSetting(initialValue: pumpManager.state.insulinType, supportedInsulinTypes: InsulinType.allCases, allowUnsetInsulinType: true) { (newType) in
                    self.pumpManager.state.insulinType = newType
                }
                let vc = DismissibleHostingController(rootView: view) {
                    tableView.reloadRows(at: [indexPath], with: .automatic)
                }
                vc.title = LocalizedString("Insulin Type", comment: "Controller title for insulin type selection screen")
                show(vc, sender: sender)
            case .reservoirRemaining:
                let vc = TextFieldTableViewController()
                vc.value = String(format: "%.1f", pumpManager.state.reservoirUnitsRemaining)
                vc.unit = "U"
                vc.keyboardType = .decimalPad
                vc.indexPath = indexPath
                vc.delegate = self
                show(vc, sender: sender)
            case .batteryRemaining:
                let vc = PercentageTextFieldTableViewController()
                vc.percentage = pumpManager.status.pumpBatteryChargeRemaining
                vc.indexPath = indexPath
                vc.percentageDelegate = self
                show(vc, sender: sender)
            case .tempBasalErrorToggle, .bolusErrorToggle, .bolusCancelErrorToggle, .suspendErrorToggle, .resumeErrorToggle, .uncertainDeliveryErrorToggle:
                break
            case .lastReconciliationDate:
                tableView.deselectRow(at: indexPath, animated: true)
                tableView.beginUpdates()
                tableView.endUpdates()
            }
        case .statusProgress:
            let vc = PercentageTextFieldTableViewController()
            vc.indexPath = indexPath
            vc.percentageDelegate = self
            switch StatusProgressRow(rawValue: indexPath.row)! {
            case .percentComplete:
                vc.percentage = pumpManager.state.progressPercentComplete
            case .warningThreshold:
                vc.percentage = pumpManager.state.progressWarningThresholdPercentValue
            case .criticalThreshold:
                vc.percentage = pumpManager.state.progressCriticalThresholdPercentValue
            }
            show(vc, sender: sender)
        case .deletePump:
            let confirmVC = UIAlertController(pumpDeletionHandler: {
                self.pumpManager.notifyDelegateOfDeactivation {
                    DispatchQueue.main.async {
                        self.done()
                    }
                }
            })

            present(confirmVC, animated: true) {
                tableView.deselectRow(at: indexPath, animated: true)
            }
        default:
            tableView.deselectRow(at: indexPath, animated: true)
        }
    }

    private func suspendResumeCellTapped(_ cell: SuspendResumeTableViewCell) {
        switch cell.shownAction {
        case .resume:
            pumpManager.resumeDelivery { (error) in
                if let error = error {
                    DispatchQueue.main.async {
                        let title = LocalizedString("Error Resuming", comment: "The alert title for a resume error")
                        self.present(UIAlertController(with: error, title: title), animated: true)
                    }
                }
            }
        case .suspend:
            pumpManager.suspendDelivery { (error) in
                if let error = error {
                    DispatchQueue.main.async {
                        let title = LocalizedString("Error Suspending", comment: "The alert title for a suspend error")
                        self.present(UIAlertController(with: error, title: title), animated: true)
                    }
                }
            }
        default:
            break
        }
    }
    
    override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        switch Section(rawValue: indexPath.section)! {
        case .settings:
            switch SettingsRow(rawValue: indexPath.row)! {
            case .lastReconciliationDate:
                
                let resetAction = UIContextualAction(style: .normal, title:  "Reset") {[weak self] _,_,_ in
                    self?.pumpManager.testLastReconciliation = nil
                    tableView.reloadRows(at: [indexPath], with: .automatic)
                }
                resetAction.backgroundColor = .systemRed
                return UISwipeActionsConfiguration(actions: [resetAction])
            default:
                break
            }
        default:
            break
        }
        return nil
    }
    
}

extension MockPumpManagerSettingsViewController: DatePickerTableViewCellDelegate {
    func datePickerTableViewCellDidUpdateDate(_ cell: DatePickerTableViewCell) {
        guard let row = tableView.indexPath(for: cell)?.row else { return }

        switch SettingsRow(rawValue: row) {
        case .lastReconciliationDate?:
            pumpManager.testLastReconciliation = cell.date
        default:
            break
        }
    }
}

extension MockPumpManagerSettingsViewController: PumpManagerStatusObserver {
    public func pumpManager(_ pumpManager: PumpManager, didUpdate status: PumpManagerStatus, oldStatus: PumpManagerStatus) {
        dispatchPrecondition(condition: .onQueue(.main))

        if let suspendResumeTableViewCell = self.tableView?.cellForRow(at: IndexPath(row: ActionRow.suspendResume.rawValue, section: Section.actions.rawValue)) as? SuspendResumeTableViewCell
        {
            suspendResumeTableViewCell.basalDeliveryState = status.basalDeliveryState
        }
        
        tableView.reloadSections([Section.basalRate.rawValue], with: .automatic)
    }
}

extension MockPumpManagerSettingsViewController: TextFieldTableViewControllerDelegate {
    func textFieldTableViewControllerDidReturn(_ controller: TextFieldTableViewController) {
        update(from: controller)
    }

    func textFieldTableViewControllerDidEndEditing(_ controller: TextFieldTableViewController) {
        update(from: controller)
    }

    private func update(from controller: TextFieldTableViewController) {
        guard let indexPath = controller.indexPath else { assertionFailure(); return }
        assert(indexPath == [Section.settings.rawValue, SettingsRow.reservoirRemaining.rawValue])
        if let value = controller.value.flatMap(Double.init) {
            pumpManager.state.reservoirUnitsRemaining = max(value, 0)
        }
        tableView.reloadRows(at: [indexPath], with: .automatic)
    }
}

extension MockPumpManagerSettingsViewController: PercentageTextFieldTableViewControllerDelegate {
    func percentageTextFieldTableViewControllerDidChangePercentage(_ controller: PercentageTextFieldTableViewController) {
        guard let indexPath = controller.indexPath else {
            assertionFailure()
            return
        }

        switch indexPath {
        case [Section.settings.rawValue, SettingsRow.batteryRemaining.rawValue]:
            pumpManager.pumpBatteryChargeRemaining = controller.percentage.map { $0.clamped(to: 0...1) }
            tableView.reloadRows(at: [indexPath], with: .automatic)
        case [Section.statusProgress.rawValue, StatusProgressRow.percentComplete.rawValue]:
            pumpManager.state.progressPercentComplete = controller.percentage.map { $0.clamped(to: 0...1) }
            tableView.reloadRows(at: [indexPath], with: .automatic)
        case [Section.statusProgress.rawValue, StatusProgressRow.warningThreshold.rawValue]:
            pumpManager.state.progressWarningThresholdPercentValue = controller.percentage.map { $0.clamped(to: 0...1) }
            tableView.reloadRows(at: [indexPath], with: .automatic)
        case [Section.statusProgress.rawValue, StatusProgressRow.criticalThreshold.rawValue]:
            pumpManager.state.progressCriticalThresholdPercentValue = controller.percentage.map { $0.clamped(to: 0...1) }
            tableView.reloadRows(at: [indexPath], with: .automatic)
        default:
            assertionFailure()
        }
    }
}

private extension UIAlertController {
    convenience init(pumpDeletionHandler handler: @escaping () -> Void) {
        self.init(
            title: nil,
            message: "Are you sure you want to delete this pump?",
            preferredStyle: .actionSheet
        )

        addAction(UIAlertAction(
            title: "Delete Pump",
            style: .destructive,
            handler: { _ in handler() }
        ))

        addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
    }

    convenience init(title: String, error: Error) {

        let message: String

        if let localizedError = error as? LocalizedError {
            let sentenceFormat = LocalizedString("%@.", comment: "Appends a full-stop to a statement")
            message = [localizedError.failureReason, localizedError.recoverySuggestion].compactMap({ $0 }).map({
                String(format: sentenceFormat, $0)
            }).joined(separator: "\n")
        } else {
            message = String(describing: error)
        }

        self.init(
            title: title,
            message: message,
            preferredStyle: .alert
        )

        addAction(UIAlertAction(
            title: LocalizedString("OK", comment: "Button title to acknowledge error"),
            style: .default,
            handler: nil
        ))
    }
}

extension MockPumpManagerSettingsViewController: SupportedRangeTableViewControllerDelegate {
    func supportedRangeDidUpdate(_ controller: SupportedRangeTableViewController) {
        guard let indexPath = controller.indexPath else {
            assertionFailure()
            return
        }

        let rangeMin = Int(controller.minValue/controller.stepSize)
        let rangeMax = Int(controller.maxValue/controller.stepSize)
        let rangeStep = 1/controller.stepSize
        let values: [Double] = (rangeMin...rangeMax).map { Double($0) / rangeStep }
        
        switch indexPath {
        case [Section.settings.rawValue, SettingsRow.supportedBasalRates.rawValue]:
            pumpManager.state.supportedBasalRates = values
            tableView.reloadRows(at: [indexPath], with: .automatic)
        case [Section.settings.rawValue, SettingsRow.supportedBolusVolumes.rawValue]:
            pumpManager.state.supportedBolusVolumes = values
            tableView.reloadRows(at: [indexPath], with: .automatic)
        default:
            assertionFailure()
        }
    }
}

fileprivate extension NewPumpEvent {
    init(alarmAt date: Date, alarmType: PumpAlarmType? = nil) {
        self.init(date: date,
                  dose: nil,
                  raw: Data(UUID().uuidString.utf8),
                  title: "alarm[\(alarmType?.rawValue ?? "")]",
                  type: .alarm,
                  alarmType: alarmType)
    }

    init(alarmClearAt date: Date) {
        self.init(date: date,
                  dose: nil,
                  raw: Data(UUID().uuidString.utf8),
                  title: "alarmClear",
                  type: .alarmClear)
    }
}
