import Foundation

extension UserDefaults {
    private enum Keys {
        static let liveActivityOrder = "liveActivityOrder"
    }

    func loadLiveActivityOrderFromUserDefaults() -> [LiveActivityAttributes.LiveActivityItem]? {
        if let itemStrings = stringArray(forKey: Keys.liveActivityOrder) {
            return itemStrings.map { string in
                if string == "" {
                    return .empty
                } else {
                    return LiveActivityAttributes.LiveActivityItem(rawValue: string) ?? .empty
                }
            }
        }
        return nil
    }
}

extension LiveActivityAttributes.ContentState {
    static func formatGlucose(_ value: Int, units: GlucoseUnits, forceSign: Bool) -> String {
        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.maximumFractionDigits = 0
        if units == .mmolL {
            formatter.minimumFractionDigits = 1
            formatter.maximumFractionDigits = 1
        }
        if forceSign {
            formatter.positivePrefix = formatter.plusSign
        }
        formatter.roundingMode = .halfUp

        return formatter
            .string(from: units == .mmolL ? value.asMmolL as NSNumber : NSNumber(value: value))!
    }

    static func calculateChange(chart: [GlucoseData], units: GlucoseUnits) -> String {
        guard chart.count > 2 else { return "" }

        let formatter = NumberFormatter()
        formatter.numberStyle = .decimal
        formatter.maximumFractionDigits = 1
        formatter.positivePrefix = "  +"
        formatter.negativePrefix = "  -"

        var lastGlucose = Decimal(chart.first?.glucose ?? 0)
        var secondLastGlucose = Decimal(chart.dropFirst().first?.glucose ?? 0)
        if units == .mmolL {
            lastGlucose = lastGlucose.asMmolL
            secondLastGlucose = secondLastGlucose.asMmolL

            formatter.minimumFractionDigits = 1
            formatter.maximumFractionDigits = 1
        }

        let delta = lastGlucose - secondLastGlucose
        return formatter.string(from: delta as NSNumber) ?? "--"
    }

    init(
        new bg: GlucoseData,
        prev _: GlucoseData?,
        units: GlucoseUnits,
        chart: [GlucoseData],
        settings: TrioSettings,
        determination: DeterminationData?,
        iob: Decimal?,
        override: OverrideData?,
        tempTarget: TempTargetData?,
        widgetItems: [LiveActivityAttributes.LiveActivityItem]?
    ) {
        let glucose = bg.glucose
        let formattedBG = Self.formatGlucose(Int(glucose), units: units, forceSign: false)
        var rotationDegrees = 0.0

        switch bg.direction {
        case .doubleUp,
             .singleUp,
             .tripleUp:
            rotationDegrees = -90
        case .fortyFiveUp:
            rotationDegrees = -45
        case .flat:
            rotationDegrees = 0
        case .fortyFiveDown:
            rotationDegrees = 45
        case .doubleDown,
             .singleDown,
             .tripleDown:
            rotationDegrees = 90
        case nil,
             .notComputable,
             .rateOutOfRange:
            rotationDegrees = 0
        default:
            rotationDegrees = 0
        }

        let trendString = bg.direction?.symbol as? String
        let change = Self.calculateChange(chart: chart, units: units)

        let detailedState = LiveActivityAttributes.ContentAdditionalState(
            chart: chart.map { LiveActivityAttributes.ChartItem(value: Decimal($0.glucose), date: $0.date) },
            rotationDegrees: rotationDegrees,
            cob: Decimal(determination?.cob ?? 0),
            iob: iob ?? 0 as Decimal,
            tdd: determination?.tdd ?? 0 as Decimal,
            isOverrideActive: override?.isActive ?? false,
            overrideName: override?.overrideName ?? "Override",
            overrideDate: override?.date ?? Date(),
            overrideDuration: override?.duration ?? 0,
            overrideTarget: override?.target ?? 0,
            isTempTargetActive: tempTarget?.isActive ?? false,
            tempTargetName: tempTarget?.tempTargetName ?? "Temp Target",
            tempTargetDate: tempTarget?.date ?? Date(),
            tempTargetDuration: tempTarget?.duration ?? 0,
            tempTargetTarget: tempTarget?.target ?? 0,
            widgetItems: widgetItems ?? [], // set empty array here to silence compiler; this can never be nil
            minForecast: settings.displayGlucoseForecasts && settings.forecastDisplayType == .cone
                ? (determination?.minForecast ?? []) : [],
            maxForecast: settings.displayGlucoseForecasts && settings.forecastDisplayType == .cone
                ? (determination?.maxForecast ?? []) : [],
            forecastLines: settings.displayGlucoseForecasts && settings.forecastDisplayType == .lines
                ? (determination?.forecastLines ?? [])
                .map { LiveActivityAttributes.ForecastLine(type: $0.type, values: $0.values) }
                : [],
            forecastDisplayType: settings.forecastDisplayType.rawValue
        )

        self.init(
            unit: settings.units.rawValue,
            bg: formattedBG,
            direction: trendString,
            change: change,
            date: determination?.date ?? nil,
            highGlucose: settings.high,
            lowGlucose: settings.low,
            target: determination?.target ?? 100 as Decimal,
            glucoseColorScheme: settings.glucoseColorScheme.rawValue,
            useDetailedViewIOS: settings.lockScreenView == .detailed,
            useDetailedViewWatchOS: settings.smartStackView == .detailed,
            detailedViewState: detailedState,
            isInitialState: false
        )
    }
}
