import Foundation

// District Companion interaction contract v1.
// Platform-neutral reference types: connect these to production voice, model,
// navigation, and action services rather than treating the prototype timers as APIs.

public enum CompanionConversationState: String, Codable, CaseIterable, Sendable {
    case waking
    case ready
    case listening
    case acknowledged
    case thinking
    case clarification
    case awaitingConfirmation = "awaiting-confirmation"
    case takingAction = "taking-action"
    case speaking
    case completed
}

public enum CompanionActivityKind: String, Codable, Sendable {
    case thinking
    case searching
}

public enum CompanionMicrophonePermission: String, Codable, Sendable {
    case unknown
    case granted
    case denied
}

public enum CompanionSurfaceState: String, Codable, Sendable {
    case collapsed
    case quickActions = "quick-actions"
    case expanded
}

public enum CompanionActionStepStatus: String, Codable, Sendable {
    case planned
    case active
    case committed
    case cancelled
}

public enum CompanionEvent: String, Codable, Sendable {
    case showQuickActions = "SHOW_QUICK_ACTIONS"
    case hideQuickActions = "HIDE_QUICK_ACTIONS"
    case open = "OPEN"
    case collapse = "COLLAPSE"
    case wakeFinished = "WAKE_FINISHED"
    case startVoice = "START_VOICE"
    case requestMicAccess = "REQUEST_MIC_ACCESS"
    case grantPermission = "GRANT_PERMISSION"
    case denyPermission = "DENY_PERMISSION"
    case resetPermission = "RESET_PERMISSION"
    case submitPrompt = "SUBMIT_PROMPT"
    case beginThinking = "BEGIN_THINKING"
    case resolveInput = "RESOLVE_INPUT"
    case confirmAction = "CONFIRM_ACTION"
    case declineAction = "DECLINE_ACTION"
    case advanceAction = "ADVANCE_ACTION"
    case speakingFinished = "SPEAKING_FINISHED"
    case completionFinished = "COMPLETION_FINISHED"
    case toggleMic = "TOGGLE_MIC"
    case toggleKeyboard = "TOGGLE_KEYBOARD"
}

public struct CompanionExchange: Codable, Equatable, Sendable {
    public var userText: String
    public var assistantText: String

    public init(userText: String = "", assistantText: String) {
        self.userText = userText
        self.assistantText = assistantText
    }
}

public struct CompanionActionStep: Identifiable, Codable, Equatable, Sendable {
    public let id: String
    public let label: String
    public var status: CompanionActionStepStatus

    public init(id: String, label: String, status: CompanionActionStepStatus = .planned) {
        self.id = id
        self.label = label
        self.status = status
    }
}

public struct CompanionSnapshot: Codable, Equatable, Sendable {
    // Conversation and capability conditions intentionally remain independent.
    public var conversationState: CompanionConversationState
    public var activityKind: CompanionActivityKind
    public var surfaceState: CompanionSurfaceState
    public var micPermission: CompanionMicrophonePermission
    public var micEnabled: Bool
    public var captureActive: Bool
    public var keyboardOpen: Bool
    public var completionResidual: Bool
    public var exchange: CompanionExchange
    public var actionSteps: [CompanionActionStep]

    public init(
        conversationState: CompanionConversationState = .ready,
        activityKind: CompanionActivityKind = .thinking,
        surfaceState: CompanionSurfaceState = .collapsed,
        micPermission: CompanionMicrophonePermission = .unknown,
        micEnabled: Bool = true,
        captureActive: Bool = false,
        keyboardOpen: Bool = false,
        completionResidual: Bool = false,
        exchange: CompanionExchange = .init(assistantText: "Tap the microphone and tell me what you want to do."),
        actionSteps: [CompanionActionStep] = []
    ) {
        self.conversationState = conversationState
        self.activityKind = activityKind
        self.surfaceState = surfaceState
        self.micPermission = micPermission
        self.micEnabled = micEnabled
        self.captureActive = captureActive
        self.keyboardOpen = keyboardOpen
        self.completionResidual = completionResidual
        self.exchange = exchange
        self.actionSteps = actionSteps
    }
}

public enum CompanionPrototypeTiming {
    // Demo pacing only. Production should advance from service events, not timers.
    public static let wake: TimeInterval = 0.85
    public static let acknowledgement: TimeInterval = 0.50
    public static let resolution: TimeInterval = 0.95
    public static let completedHold: TimeInterval = 1.50
    public static let naturalBlinkCycle: TimeInterval = 7.30
}

public enum CompanionSafetyRule {
    /// Purchases, bookings, cancellations, and account changes require explicit confirmation.
    public static func requiresConfirmation(for category: String) -> Bool {
        ["purchase", "booking", "cancellation", "account-change"].contains(category)
    }

    /// During app actions, only an explicit tap should request interruption.
    public static func canInterruptWithVoice(_ state: CompanionConversationState) -> Bool {
        state == .speaking
    }
}
