import CodexBarCore
import Foundation

enum MenuBarIconStyle: String, CaseIterable {
    case critters
    case bars
    case iconAndPercent

    var label: String {
        switch self {
        case .critters: L("menu_bar_style_critters")
        case .bars: L("menu_bar_style_bars")
        case .iconAndPercent: L("menu_bar_style_icon_percent")
        }
    }
}

enum SwitcherRowsOption: String, CaseIterable {
    case icons
    case progress

    var label: String {
        switch self {
        case .icons: L("switcher_rows_icons")
        case .progress: L("switcher_rows_progress")
        }
    }
}

enum UsageBarsFillOption: String, CaseIterable {
    case remaining
    case used

    var label: String {
        switch self {
        case .remaining: L("usage_bars_fill_remaining")
        case .used: L("usage_bars_fill_used")
        }
    }
}

enum ResetTimesOption: String, CaseIterable {
    case countdown
    case clock

    var label: String {
        switch self {
        case .countdown: L("reset_times_countdown")
        case .clock: L("reset_times_clock")
        }
    }
}

enum ConfettiCelebrationOption: String, CaseIterable {
    case off
    case session
    case weekly
    case both

    var label: String {
        switch self {
        case .off: L("confetti_option_off")
        case .session: L("confetti_option_session")
        case .weekly: L("confetti_option_weekly")
        case .both: L("confetti_option_both")
        }
    }
}

enum CostSummaryOption: String, CaseIterable {
    case off
    case inlineSummary
    case costSubmenu
    case both

    var label: String {
        switch self {
        case .off: L("cost_summary_off")
        case .inlineSummary: CostSummaryDisplayStyle.inlineSummary.label
        case .costSubmenu: CostSummaryDisplayStyle.costSubmenu.label
        case .both: CostSummaryDisplayStyle.both.label
        }
    }
}

enum AgentSessionLabelStyle: String, CaseIterable {
    case project
    case descriptive
    case descriptiveAndProject

    var label: String {
        switch self {
        case .project: L("agent_session_label_project")
        case .descriptive: L("agent_session_label_descriptive")
        case .descriptiveAndProject: L("agent_session_label_descriptive_and_project")
        }
    }

    func label(for session: AgentSession) -> String {
        let project = session.projectName?.trimmingCharacters(in: .whitespacesAndNewlines)
        let descriptive = session.sessionName?.trimmingCharacters(in: .whitespacesAndNewlines)
        switch self {
        case .project:
            return project?.nilIfEmpty ?? L("agent_session_unknown_project")
        case .descriptive:
            return descriptive?.nilIfEmpty ?? project?.nilIfEmpty ?? L("agent_session_unknown_project")
        case .descriptiveAndProject:
            guard let descriptive = descriptive?.nilIfEmpty else {
                return project?.nilIfEmpty ?? L("agent_session_unknown_project")
            }
            guard let project = project?.nilIfEmpty,
                  descriptive.caseInsensitiveCompare(project) != .orderedSame
            else { return descriptive }
            return "\(descriptive) · \(project)"
        }
    }
}

extension String {
    fileprivate var nilIfEmpty: String? {
        self.isEmpty ? nil : self
    }
}

extension SettingsStore {
    var menuBarIconStyle: MenuBarIconStyle {
        get {
            if self.menuBarShowsBrandIconWithPercent {
                return .iconAndPercent
            }
            return self.menuBarHidesCritters ? .bars : .critters
        }
        set {
            switch newValue {
            case .critters:
                self.menuBarShowsBrandIconWithPercent = false
                self.menuBarHidesCritters = false
            case .bars:
                self.menuBarShowsBrandIconWithPercent = false
                self.menuBarHidesCritters = true
            case .iconAndPercent:
                self.menuBarShowsBrandIconWithPercent = true
            }
        }
    }

    var switcherRowsOption: SwitcherRowsOption {
        get { self.switcherShowsIcons ? .icons : .progress }
        set { self.switcherShowsIcons = newValue == .icons }
    }

    var usageBarsFillOption: UsageBarsFillOption {
        get { self.usageBarsShowUsed ? .used : .remaining }
        set { self.usageBarsShowUsed = newValue == .used }
    }

    var resetTimesOption: ResetTimesOption {
        get { self.resetTimesShowAbsolute ? .clock : .countdown }
        set { self.resetTimesShowAbsolute = newValue == .clock }
    }

    var confettiCelebrationOption: ConfettiCelebrationOption {
        get {
            switch (self.confettiOnSessionLimitResetsEnabled, self.confettiOnWeeklyLimitResetsEnabled) {
            case (false, false): .off
            case (true, false): .session
            case (false, true): .weekly
            case (true, true): .both
            }
        }
        set {
            self.confettiOnSessionLimitResetsEnabled = newValue == .session || newValue == .both
            self.confettiOnWeeklyLimitResetsEnabled = newValue == .weekly || newValue == .both
        }
    }

    var costSummaryOption: CostSummaryOption {
        get {
            guard self.costUsageEnabled else { return .off }
            switch self.costSummaryDisplayStyle {
            case .inlineSummary: return .inlineSummary
            case .costSubmenu: return .costSubmenu
            case .both: return .both
            }
        }
        set {
            switch newValue {
            case .off:
                self.costUsageEnabled = false
            case .inlineSummary:
                self.costSummaryDisplayStyle = .inlineSummary
                self.costUsageEnabled = true
            case .costSubmenu:
                self.costSummaryDisplayStyle = .costSubmenu
                self.costUsageEnabled = true
            case .both:
                self.costSummaryDisplayStyle = .both
                self.costUsageEnabled = true
            }
        }
    }

    func menuBarMetricPreference(for provider: UsageProvider) -> MenuBarMetricPreference {
        let raw = self.menuBarMetricPreferencesRaw[provider.rawValue] ?? ""
        let preference = MenuBarMetricPreference(rawValue: raw) ?? .automatic
        return self.menuBarMetricSupports(preference, for: provider) ? preference : .automatic
    }

    func setMenuBarMetricPreference(_ preference: MenuBarMetricPreference, for provider: UsageProvider) {
        let resolved = self.menuBarMetricSupports(preference, for: provider) ? preference : .automatic
        self.menuBarMetricPreferencesRaw[provider.rawValue] = resolved.rawValue
    }

    func menuBarMetricSupportsAverage(for provider: UsageProvider) -> Bool {
        self.menuBarMetricCapabilities(for: provider).supports(.average)
    }

    func menuBarMetricSupportsPrimaryAndSecondary(for provider: UsageProvider) -> Bool {
        self.menuBarMetricCapabilities(for: provider).supports(.primaryAndSecondary)
    }

    func menuBarMetricSupportsTertiary(for provider: UsageProvider) -> Bool {
        self.menuBarMetricCapabilities(for: provider).supports(.tertiary)
    }

    func menuBarMetricSupportsTertiary(for provider: UsageProvider, snapshot: UsageSnapshot?) -> Bool {
        let capabilities = self.menuBarMetricCapabilities(for: provider)
        guard capabilities.supports(.tertiary) else { return false }
        return !capabilities.tertiaryRequiresWindow || snapshot?.tertiary != nil
    }

    func menuBarMetricSupportsExtraUsage(for provider: UsageProvider) -> Bool {
        self.menuBarMetricCapabilities(for: provider).supports(.extraUsage)
    }

    func menuBarMetricSupportsExtraUsage(for provider: UsageProvider, snapshot: UsageSnapshot?) -> Bool {
        guard self.menuBarMetricSupportsExtraUsage(for: provider) else { return false }
        guard let cost = snapshot?.providerCost else { return false }
        return cost.limit > 0
    }

    func menuBarMetricPreference(for provider: UsageProvider, snapshot: UsageSnapshot?) -> MenuBarMetricPreference {
        let preference = self.menuBarMetricPreference(for: provider)
        if preference == .tertiary,
           !self.menuBarMetricSupportsTertiary(for: provider, snapshot: snapshot)
        {
            return .automatic
        }
        if preference == .extraUsage,
           !self.menuBarMetricSupportsExtraUsage(for: provider, snapshot: snapshot)
        {
            return .automatic
        }
        return preference
    }

    func isCostUsageEffectivelyEnabled(for provider: UsageProvider) -> Bool {
        let isEnabled = self.costUsageEnabled ||
            (provider == .codex && self.codexLocalSessionCostLedgerEnabled)
        return isEnabled && ProviderDescriptorRegistry.descriptor(for: provider).tokenCost.supportsTokenCost
    }

    var resetTimeDisplayStyle: ResetTimeDisplayStyle {
        self.resetTimesShowAbsolute ? .absolute : .countdown
    }

    private func menuBarMetricCapabilities(for provider: UsageProvider) -> ProviderMenuBarMetricCapabilities {
        ProviderDescriptorRegistry.descriptor(for: provider).menuBarMetrics
    }

    private func menuBarMetricSupports(_ preference: MenuBarMetricPreference, for provider: UsageProvider) -> Bool {
        self.menuBarMetricCapabilities(for: provider).supports(preference.providerMetric)
    }
}

extension MenuBarMetricPreference {
    fileprivate var providerMetric: ProviderMenuBarMetric {
        switch self {
        case .automatic: .automatic
        case .primary: .primary
        case .secondary: .secondary
        case .primaryAndSecondary: .primaryAndSecondary
        case .tertiary: .tertiary
        case .extraUsage: .extraUsage
        case .average: .average
        case .monthlyPlan: .monthlyPlan
        }
    }
}
