import SwiftUI

struct TalkProTab: View {
    @Environment(NodeAppModel.self) private var appModel
    @AppStorage("talk.enabled") private var talkEnabled: Bool = false
    @AppStorage(TalkSpeechLocale.storageKey) private var talkSpeechLocale: String = TalkSpeechLocale.automaticID
    @AppStorage(TalkDefaults.speakerphoneEnabledKey) private var talkSpeakerphoneEnabled: Bool =
        TalkDefaults.speakerphoneEnabledByDefault
    @AppStorage("talk.background.enabled") private var talkBackgroundEnabled: Bool = false
    @State private var showPermissionPrompt = false
    @State private var showTalkIssueDetails = false
    let headerLeadingAction: OpenClawSidebarHeaderAction?
    let ownsNavigationStack: Bool
    var openSettings: () -> Void
    var openVoiceSettings: () -> Void

    init(
        headerLeadingAction: OpenClawSidebarHeaderAction? = nil,
        ownsNavigationStack: Bool = true,
        openSettings: @escaping () -> Void,
        openVoiceSettings: (() -> Void)? = nil)
    {
        self.headerLeadingAction = headerLeadingAction
        self.ownsNavigationStack = ownsNavigationStack
        self.openSettings = openSettings
        self.openVoiceSettings = openVoiceSettings ?? openSettings
    }

    private var state: TalkProState {
        TalkProState(
            gatewayConnected: self.gatewayConnected,
            isDemoMode: self.appModel.isAppleReviewDemoModeEnabled,
            isEnabled: self.appModel.talkMode.isEnabled || self.talkEnabled,
            statusText: self.appModel.talkMode.statusText,
            isConfigLoaded: self.appModel.talkMode.gatewayTalkConfigLoaded,
            isListening: self.appModel.talkMode.isListening,
            isSpeaking: self.appModel.talkMode.isSpeaking,
            isUserSpeechDetected: self.appModel.talkMode.isUserSpeechDetected,
            permissionState: self.appModel.talkMode.gatewayTalkPermissionState)
    }

    var body: some View {
        Group {
            if self.ownsNavigationStack {
                NavigationStack {
                    self.content
                }
            } else {
                self.content
            }
        }
        .sheet(isPresented: self.$showPermissionPrompt) {
            NavigationStack {
                TalkPermissionPromptView(
                    style: .sheet,
                    onPermissionReady: {
                        self.showPermissionPrompt = false
                        self.startTalk()
                    })
                    .padding()
                    .navigationTitle("Enable Talk")
                    .toolbar {
                        ToolbarItem(placement: .cancellationAction) {
                            Button {
                                self.showPermissionPrompt = false
                            } label: {
                                Text("Not Now")
                                    .font(OpenClawType.subheadSemiBold)
                            }
                        }
                    }
            }
            .presentationDetents([.medium, .large])
            .openClawSheetChrome()
        }
        .sheet(isPresented: self.$showTalkIssueDetails) {
            if let fallbackIssue = self.fallbackIssue {
                TalkRuntimeIssueDetailsSheet(
                    issue: fallbackIssue,
                    onOpenSettings: self.openVoiceSettings)
                    .openClawSheetChrome()
            }
        }
        .onAppear { self.alignPersistedTalkState() }
    }

    private var content: some View {
        List {
            if let fallbackIssue = self.fallbackIssue {
                Section {
                    TalkRuntimeIssueBanner(
                        issue: fallbackIssue,
                        onOpenSettings: self.openVoiceSettings,
                        onShowDetails: {
                            self.showTalkIssueDetails = true
                        })
                }
                .listRowInsets(EdgeInsets())
                .listRowBackground(Color.clear)
            }
            self.heroSection
            self.conversationSection
            self.voiceModeSection
            self.controlsSection
        }
        .navigationTitle("Talk")
        .toolbar {
            if let headerLeadingAction {
                ToolbarItem(placement: .topBarLeading) {
                    OpenClawSidebarRevealButton(action: headerLeadingAction)
                }
            }
        }
    }

    private var heroSection: some View {
        Section {
            VStack(spacing: 16) {
                TalkSiriWaveView(mode: self.state.waveformMode(micLevel: self.appModel.talkMode.micLevel))
                    .frame(height: 130)
                    .accessibilityHidden(true)

                VStack(spacing: 4) {
                    Text(self.state.title)
                        .font(OpenClawType.title3SemiBold)
                        .multilineTextAlignment(.center)
                    Text(self.heroSubtitle)
                        .font(OpenClawType.subhead)
                        .foregroundStyle(.secondary)
                        .multilineTextAlignment(.center)
                }

                Button(action: self.handlePrimaryAction) {
                    Label(self.state.primaryButtonTitle, systemImage: self.state.primaryButtonIcon)
                        .font(OpenClawType.subheadSemiBold)
                        // Match the icon to the label; otherwise the symbol picks up the tint color.
                        .foregroundStyle(.white)
                        .frame(maxWidth: .infinity)
                }
                .buttonStyle(.borderedProminent)
                .controlSize(.large)
                .tint(self.state.color)
                .disabled(self.state.primaryAction == .waiting)
            }
            .frame(maxWidth: .infinity)
            .padding(.vertical, 8)
            .listRowBackground(Color.clear)
        }
    }

    private var conversationSection: some View {
        Section("Conversation") {
            LabeledContent("Agent", value: self.appModel.chatAgentName)
            LabeledContent("Session", value: self.appModel.chatSessionKey)
            LabeledContent("Runtime", value: self.appModel.talkMode.statusText)
        }
    }

    private var voiceModeSection: some View {
        Section("Voice Mode") {
            LabeledContent("Configured", value: self.appModel.talkMode.gatewayTalkVoiceModeTitle)
            LabeledContent("Active", value: self.activeModeText)
            LabeledContent("Transport", value: self.transportText)
            if let issueText = self.talkIssueText {
                LabeledContent("Last issue", value: issueText)
            }
            LabeledContent("Permission", value: self.permissionText)
            LabeledContent("Speech language", value: self.speechLocaleText)
        }
    }

    private var controlsSection: some View {
        Section("Controls") {
            Toggle(isOn: self.talkSpeakerphoneBinding) {
                Text("Speakerphone")
                    .font(OpenClawType.body)
            }
            .accessibilityIdentifier("talk-speakerphone-control")
            Toggle(isOn: self.$talkBackgroundEnabled) {
                Text("Background listening")
                    .font(OpenClawType.body)
            }
            .accessibilityIdentifier("talk-background-listening-control")
            Button(action: self.openVoiceSettings) {
                HStack {
                    Label("Voice & Talk Settings", systemImage: "slider.horizontal.3")
                        .font(OpenClawType.body)
                        .foregroundStyle(.primary)
                    Spacer()
                    Image(systemName: "chevron.forward")
                        .font(OpenClawType.footnoteSemiBold)
                        .foregroundStyle(.tertiary)
                }
                .contentShape(Rectangle())
            }
            .buttonStyle(.plain)
            .accessibilityIdentifier("talk-voice-settings-control")
        }
    }

    private var gatewayConnected: Bool {
        !self.appModel.isAppleReviewDemoModeEnabled &&
            GatewayStatusBuilder.build(appModel: self.appModel) == .connected
    }

    private var fallbackIssue: TalkRuntimeIssue? {
        guard self.gatewayConnected else { return nil }
        return self.appModel.talkMode.gatewayTalkCurrentFallbackIssue
    }

    private var heroSubtitle: String {
        if self.state
            .prefersPermissionCopy { return "Gateway approval is required before this phone can capture voice." }
        if self.appModel.isAppleReviewDemoModeEnabled { return "Voice is disabled in Apple Review demo mode." }
        if !self.gatewayConnected { return "Connect to your gateway to start a voice conversation." }
        if !self.appModel.talkMode.gatewayTalkConfigLoaded {
            return "Open Voice settings after the gateway loads Talk configuration."
        }
        let subtitle = (appModel.talkMode.gatewayTalkVoiceModeSubtitle ?? "")
            .trimmingCharacters(in: .whitespacesAndNewlines)
        if !subtitle.isEmpty { return subtitle }
        return "Routes voice to \(self.appModel.chatAgentName)."
    }

    private var transportText: String {
        let provider = self.appModel.talkMode.gatewayTalkProviderLabel.trimmingCharacters(in: .whitespacesAndNewlines)
        let transport = self.appModel.talkMode.gatewayTalkTransportLabel.trimmingCharacters(in: .whitespacesAndNewlines)
        if provider.isEmpty || provider == "Not loaded" { return transport.isEmpty ? "Not loaded" : transport }
        if transport.isEmpty || transport == "Not loaded" { return provider }
        return "\(provider) • \(transport)"
    }

    private var activeModeText: String {
        let title = self.appModel.talkMode.gatewayTalkActiveModeTitle.trimmingCharacters(in: .whitespacesAndNewlines)
        let subtitle = (appModel.talkMode.gatewayTalkActiveModeSubtitle ?? "")
            .trimmingCharacters(in: .whitespacesAndNewlines)
        if title.isEmpty { return "Not active" }
        if subtitle.isEmpty { return title }
        return "\(title) • \(subtitle)"
    }

    private var talkIssueText: String? {
        let text = (appModel.talkMode.gatewayTalkLastIssueText ?? "")
            .trimmingCharacters(in: .whitespacesAndNewlines)
        return text.isEmpty ? nil : text
    }

    private var permissionText: String {
        if let failure = appModel.talkMode.gatewayTalkPermissionState.failureMessage {
            return failure
        }
        return self.appModel.talkMode.gatewayTalkPermissionState.statusLabel
    }

    private var speechLocaleText: String {
        if self.talkSpeechLocale == TalkSpeechLocale.automaticID { return "Automatic" }
        return self.talkSpeechLocale
    }

    private func alignPersistedTalkState() {
        if self.appModel.isAppleReviewDemoModeEnabled,
           self.talkEnabled || self.appModel.talkMode.isEnabled
        {
            self.stopTalk()
        } else if self.appModel.talkMode.gatewayTalkPermissionState.requiresTalkPermissionAction,
                  self.talkEnabled || self.appModel.talkMode.isEnabled
        {
            self.stopTalk()
        } else if self.talkEnabled != self.appModel.talkMode.isEnabled {
            self.appModel.setTalkEnabled(self.talkEnabled)
        }
    }

    private var talkSpeakerphoneBinding: Binding<Bool> {
        Binding(
            get: { self.talkSpeakerphoneEnabled },
            set: { enabled in
                self.talkSpeakerphoneEnabled = enabled
                self.appModel.setTalkSpeakerphoneEnabled(enabled)
            })
    }

    private func handlePrimaryAction() {
        switch self.state.primaryAction {
        case .start:
            self.startTalk()
        case .stop:
            self.stopTalk()
        case .enablePermission:
            self.stopTalk()
            self.showPermissionPrompt = true
        case .openSettings:
            self.openPrimarySettings()
        case .waiting:
            break
        }
    }

    private func startTalk() {
        guard !self.appModel.isAppleReviewDemoModeEnabled else { return }
        self.talkEnabled = true
        self.appModel.talkMode.updateMainSessionKey(self.appModel.chatSessionKey)
        self.appModel.setTalkEnabled(true)
    }

    private func stopTalk() {
        self.talkEnabled = false
        self.appModel.setTalkEnabled(false)
    }

    private func openPrimarySettings() {
        if self.gatewayConnected {
            self.openVoiceSettings()
        } else {
            self.openSettings()
        }
    }
}

enum TalkProPrimaryAction: Equatable {
    case start
    case stop
    case enablePermission
    case openSettings
    case waiting
}

enum TalkProWaveformMode: Equatable {
    case level(Double)
    case inputSpeech
    case speaking
    case indeterminate
    case still
}

struct TalkProState: Equatable {
    let gatewayConnected: Bool
    let isDemoMode: Bool
    let isEnabled: Bool
    let statusText: String
    let isConfigLoaded: Bool
    let isListening: Bool
    let isSpeaking: Bool
    let isUserSpeechDetected: Bool
    let permissionState: TalkGatewayPermissionState

    private var normalizedStatus: String {
        self.statusText.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
    }

    var title: String {
        if self.isDemoMode { return "Demo mode only" }
        if !self.gatewayConnected { return "Gateway offline" }
        switch self.permissionState {
        case .missingScope, .requestFailed:
            return "Gateway permission required"
        case .requestingUpgrade:
            return "Requesting approval"
        case .upgradeRequested:
            return "Approval requested"
        case .apiKeyMissing:
            return "Voice API key missing"
        case .loadFailed:
            return "Voice config failed"
        default:
            break
        }
        if !self.isConfigLoaded { return "Voice config unavailable" }
        if self.isSpeaking { return "Speaking" }
        if self.isListening { return "Listening" }
        if self.normalizedStatus.contains("connecting") { return "Connecting" }
        if self.normalizedStatus.contains("thinking") { return "Asking OpenClaw" }
        if self.isEnabled { return "Ready to talk" }
        return "Talk is off"
    }

    var color: Color {
        if self.isDemoMode { return .secondary }
        if !self.gatewayConnected { return .secondary }
        switch self.permissionState {
        case .requestFailed, .loadFailed:
            return OpenClawBrand.danger
        case .missingScope, .requestingUpgrade, .upgradeRequested, .apiKeyMissing:
            return OpenClawBrand.warn
        default:
            if !self.isConfigLoaded { return OpenClawBrand.warn }
            return self.isEnabled ? OpenClawBrand.ok : OpenClawBrand.accentHot
        }
    }

    var primaryAction: TalkProPrimaryAction {
        if self.isDemoMode { return .waiting }
        if !self.gatewayConnected { return .openSettings }
        switch self.permissionState {
        case .missingScope, .requestFailed:
            return .enablePermission
        case .requestingUpgrade, .upgradeRequested:
            return .waiting
        case .apiKeyMissing, .loadFailed:
            return .openSettings
        default:
            return self.isEnabled ? .stop : .start
        }
    }

    var primaryButtonTitle: String {
        switch self.primaryAction {
        case .start: "Start Talk"
        case .stop: "Stop Talk"
        case .enablePermission: "Enable Talk"
        case .openSettings: self.gatewayConnected ? "Open Voice Settings" : "Open Gateway Settings"
        case .waiting: self.isDemoMode ? "Demo Mode Only" : "Waiting for Approval"
        }
    }

    var primaryButtonIcon: String {
        switch self.primaryAction {
        case .start: "play.fill"
        case .stop: "stop.fill"
        case .enablePermission: "key.fill"
        case .openSettings: "gearshape.fill"
        case .waiting: self.isDemoMode ? "lock.fill" : "hourglass"
        }
    }

    var prefersPermissionCopy: Bool {
        switch self.permissionState {
        case .missingScope, .requestingUpgrade, .upgradeRequested, .requestFailed:
            true
        default:
            false
        }
    }

    func waveformMode(micLevel: Double) -> TalkProWaveformMode {
        if self.isDemoMode { return .still }
        if !self.gatewayConnected { return .still }
        switch self.permissionState {
        case .requestingUpgrade, .upgradeRequested:
            return .indeterminate
        case .missingScope, .requestFailed, .apiKeyMissing, .loadFailed:
            return .still
        default:
            break
        }
        if !self.isConfigLoaded { return .still }
        if self.isSpeaking { return .speaking }
        if self.isListening, self.isUserSpeechDetected { return .inputSpeech }
        if self.isListening { return .level(micLevel) }
        if self.normalizedStatus.contains("connecting") || self.normalizedStatus.contains("thinking") {
            return .indeterminate
        }
        return self.isEnabled ? .indeterminate : .still
    }
}
