import CodexBarCore
import Foundation
import SwiftUI

/// Settings UI context passed to provider implementations.
///
/// Providers use this to:
/// - bind to `SettingsStore` values
/// - read current provider state from `UsageStore`
/// - surface transient status text (e.g. "Importing cookies…")
/// - request a shared confirmation alert (no provider-specific UI)
@MainActor
struct ProviderSettingsContext {
    let provider: UsageProvider
    let settings: SettingsStore
    let store: UsageStore

    let boolBinding: (ReferenceWritableKeyPath<SettingsStore, Bool>) -> Binding<Bool>
    let stringBinding: (ReferenceWritableKeyPath<SettingsStore, String>) -> Binding<String>

    let statusText: (String) -> String?
    let setStatusText: (String, String?) -> Void

    let lastAppActiveRunAt: (String) -> Date?
    let setLastAppActiveRunAt: (String, Date?) -> Void

    let requestConfirmation: (ProviderSettingsConfirmation) -> Void
    let runLoginFlow: () async -> Void

    func providerConfigBinding(_ field: ProviderConfigStringField) -> Binding<String> {
        self.settings.providerConfigBinding(provider: self.provider, field: field)
    }

    init(
        provider: UsageProvider,
        settings: SettingsStore,
        store: UsageStore,
        boolBinding: @escaping (ReferenceWritableKeyPath<SettingsStore, Bool>) -> Binding<Bool>,
        stringBinding: @escaping (ReferenceWritableKeyPath<SettingsStore, String>) -> Binding<String>,
        statusText: @escaping (String) -> String?,
        setStatusText: @escaping (String, String?) -> Void,
        lastAppActiveRunAt: @escaping (String) -> Date?,
        setLastAppActiveRunAt: @escaping (String, Date?) -> Void,
        requestConfirmation: @escaping (ProviderSettingsConfirmation) -> Void,
        runLoginFlow: @escaping () async -> Void = {})
    {
        self.provider = provider
        self.settings = settings
        self.store = store
        self.boolBinding = boolBinding
        self.stringBinding = stringBinding
        self.statusText = statusText
        self.setStatusText = setStatusText
        self.lastAppActiveRunAt = lastAppActiveRunAt
        self.setLastAppActiveRunAt = setLastAppActiveRunAt
        self.requestConfirmation = requestConfirmation
        self.runLoginFlow = runLoginFlow
    }
}

/// Shared confirmation alert descriptor.
///
/// Providers can request confirmations (e.g. permission prompts) without supplying custom UI.
@MainActor
struct ProviderSettingsConfirmation {
    let title: String
    let message: String
    let confirmTitle: String
    let onConfirm: () -> Void
}

/// Shared toggle descriptor rendered in the Providers settings pane.
@MainActor
struct ProviderSettingsToggleDescriptor: Identifiable {
    let id: String
    let title: String
    let subtitle: String
    let binding: Binding<Bool>

    /// Optional short status text shown under the toggle when enabled.
    let statusText: (() -> String?)?

    /// Optional actions shown under the toggle when enabled.
    let actions: [ProviderSettingsActionDescriptor]

    /// Optional runtime visibility gate.
    let isVisible: (() -> Bool)?

    /// Optional runtime enabled gate.
    let isEnabled: (() -> Bool)?

    /// Called whenever the toggle changes.
    let onChange: ((_ enabled: Bool) async -> Void)?

    /// Called when the app becomes active (used for "retry after permission grant" flows).
    let onAppDidBecomeActive: (() async -> Void)?

    /// Called when the view appears while the toggle is enabled.
    let onAppearWhenEnabled: (() async -> Void)?

    init(
        id: String,
        title: String,
        subtitle: String,
        binding: Binding<Bool>,
        statusText: (() -> String?)?,
        actions: [ProviderSettingsActionDescriptor],
        isVisible: (() -> Bool)?,
        isEnabled: (() -> Bool)? = nil,
        onChange: ((_ enabled: Bool) async -> Void)?,
        onAppDidBecomeActive: (() async -> Void)?,
        onAppearWhenEnabled: (() async -> Void)?)
    {
        self.id = id
        self.title = title
        self.subtitle = subtitle
        self.binding = binding
        self.statusText = statusText
        self.actions = actions
        self.isVisible = isVisible
        self.isEnabled = isEnabled
        self.onChange = onChange
        self.onAppDidBecomeActive = onAppDidBecomeActive
        self.onAppearWhenEnabled = onAppearWhenEnabled
    }
}

/// Shared text field descriptor rendered in the Providers settings pane.
@MainActor
struct ProviderSettingsFieldDescriptor: Identifiable {
    enum Kind {
        case plain
        case secure
    }

    let id: String
    let title: String
    let subtitle: String
    var footerText: String?
    let kind: Kind
    let placeholder: String?
    let binding: Binding<String>
    let actions: [ProviderSettingsActionDescriptor]
    let isVisible: (() -> Bool)?
    let onActivate: (() -> Void)?
}

/// Shared action row descriptor rendered in the Providers settings pane.
@MainActor
struct ProviderSettingsActionsDescriptor: Identifiable {
    let id: String
    let title: String
    let subtitle: String
    let actions: [ProviderSettingsActionDescriptor]
    let isVisible: (() -> Bool)?
}

/// Shared token account descriptor rendered in the Providers settings pane.
@MainActor
struct ProviderSettingsTokenAccountsDescriptor: Identifiable {
    let id: String
    let title: String
    let subtitle: String
    let placeholder: String
    let provider: UsageProvider
    let isVisible: (() -> Bool)?
    let accounts: () -> [ProviderTokenAccount]
    let activeIndex: () -> Int
    let setActiveIndex: (Int) -> Void
    let showsOrganizationField: Bool
    let showsTeamModeControls: Bool
    let addAccount: (
        _ label: String,
        _ token: String,
        _ usageScope: String?,
        _ organizationID: String?,
        _ workspaceID: String?) -> Void
    let updateAccount: (
        _ accountID: UUID,
        _ usageScope: String?,
        _ organizationID: String?,
        _ workspaceID: String?) -> Void
    let removeAccount: (_ accountID: UUID) -> Void
    let primaryAddActionTitle: String?
    let primaryAddAction: (() async -> Void)?
    let openConfigFile: () -> Void
    let reloadFromDisk: () -> Void
}

/// Shared organizations descriptor rendered in the Providers settings pane.
///
/// Used by providers that let the user opt in to additional account scopes
/// (e.g. Kilo organizations) shown alongside the personal account.
@MainActor
struct ProviderSettingsOrganizationsDescriptor: Identifiable {
    struct Entry: Identifiable {
        let id: String
        let title: String
        let subtitle: String?
        let localizesTitle: Bool
        let localizesSubtitle: Bool
        let isEnabled: Bool
        let isLocked: Bool

        init(
            id: String,
            title: String,
            subtitle: String?,
            localizesTitle: Bool = true,
            localizesSubtitle: Bool = true,
            isEnabled: Bool,
            isLocked: Bool)
        {
            self.id = id
            self.title = title
            self.subtitle = subtitle
            self.localizesTitle = localizesTitle
            self.localizesSubtitle = localizesSubtitle
            self.isEnabled = isEnabled
            self.isLocked = isLocked
        }
    }

    struct RefreshOutcome {
        let success: Bool
        let errorMessage: String?
    }

    let id: String
    let title: String
    let subtitle: String?
    let entries: () -> [Entry]
    let onToggle: (String, Bool) -> Void
    let onRefresh: () async -> RefreshOutcome
    let canRefresh: () -> Bool
}

/// Shared picker descriptor rendered in the Providers settings pane.
enum ProviderSettingsPickerPlacement: Equatable {
    case menuBar
    case connection
}

@MainActor
struct ProviderSettingsPickerDescriptor: Identifiable {
    let id: String
    let title: String
    let subtitle: String
    let placement: ProviderSettingsPickerPlacement
    let dynamicSubtitle: (() -> String?)?
    let binding: Binding<String>
    let options: [ProviderSettingsPickerOption]
    let isVisible: (() -> Bool)?
    let isEnabled: (() -> Bool)?
    let onChange: ((_ selection: String) async -> Void)?
    let trailingText: (() -> String?)?
    let trailingActions: [ProviderSettingsActionDescriptor]

    init(
        id: String,
        title: String,
        subtitle: String,
        placement: ProviderSettingsPickerPlacement = .connection,
        dynamicSubtitle: (() -> String?)? = nil,
        binding: Binding<String>,
        options: [ProviderSettingsPickerOption],
        isVisible: (() -> Bool)?,
        isEnabled: (() -> Bool)? = nil,
        onChange: ((_ selection: String) async -> Void)?,
        trailingText: (() -> String?)? = nil,
        trailingActions: [ProviderSettingsActionDescriptor] = [])
    {
        self.id = id
        self.title = title
        self.subtitle = subtitle
        self.placement = placement
        self.dynamicSubtitle = dynamicSubtitle
        self.binding = binding
        self.options = options
        self.isVisible = isVisible
        self.isEnabled = isEnabled
        self.onChange = onChange
        self.trailingText = trailingText
        self.trailingActions = trailingActions
    }
}

struct ProviderSettingsPickerOption: Identifiable {
    let id: String
    let title: String
}

/// Shared action descriptor rendered under a settings toggle.
@MainActor
struct ProviderSettingsActionDescriptor: Identifiable {
    enum Style {
        case bordered
        case link
    }

    let id: String
    let title: String
    let style: Style
    let isVisible: (() -> Bool)?
    let perform: () async -> Void
}
