import SwiftUI
import AVKit
import VoiceCatCore

struct SettingsView: View {
    @Environment(AppState.self) private var appState
    @Bindable var session: SessionState
    @StateObject private var router = IOSAudioRouter.shared
    @State private var showAdvanced = false

    // Notification feedback prefs — keys shared with VoiceCatCore's FeedbackSettings, so the
    // EventFeedback player reads the same values these toggles write.
    @AppStorage("feedback.sounds")   private var soundsEnabled = true
    @AppStorage("feedback.speech")   private var speechEnabled = false
    @AppStorage("feedback.volume")   private var soundsVolume = 1.0
    @AppStorage("feedback.selfTalk") private var selfTalkEnabled = false
    @AppStorage("feedback.ptt")      private var pttSoundEnabled = false

    var body: some View {
        NavigationStack {
            Form {
                // MARK: - Audio Preset
                Section("Audio") {
                    Picker("Preset", selection: Binding(
                        get: { router.activePreset },
                        set: { preset in router.applyPreset(preset) }
                    )) {
                        ForEach(router.availablePresets) { preset in
                            Text(preset.rawValue).tag(preset)
                        }
                    }
                    .accessibilityLabel("Audio preset")

                    Toggle("Speaker output", isOn: Binding(
                        get: { router.forceSpeaker },
                        set: { router.setForceSpeaker($0) }
                    ))
                    .accessibilityLabel("Speaker output")
                    .accessibilityHint("Routes audio to the speaker instead of the earpiece when no headphones are connected.")

                    // Surface the voice-processing state. On Voice Chat the native iOS
                    // Voice-Processing unit (VPIO) does echo cancellation, noise suppression and
                    // automatic gain control; the stereo / mono-mic / A2DP configs can't use it.
                    if router.currentConfigUsesVoiceProcessing {
                        Label("Echo cancellation & noise suppression on (iOS voice processing)",
                              systemImage: "waveform.badge.mic")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                            .accessibilityLabel("Echo cancellation and noise suppression are on")
                    } else {
                        Label("No echo cancellation in this configuration (stereo / A2DP / off)",
                              systemImage: "waveform.slash")
                            .font(.caption)
                            .foregroundStyle(.secondary)
                            .accessibilityLabel("Echo cancellation is off in this configuration")
                    }
                }

                // MARK: - Advanced Audio
                Section {
                    DisclosureGroup("Advanced Audio", isExpanded: $showAdvanced) {
                        // Input port picker (AVAudioSession.availableInputs)
                        Picker("Input Port", selection: Binding(
                            get: { router.selectedInputPortId ?? "" },
                            set: { id in
                                if !id.isEmpty { router.selectInputPort(id) }
                            }
                        )) {
                            Text("Default").tag("")
                            ForEach(router.inputPorts) { port in
                                Text(port.name).tag(port.id)
                            }
                        }
                        .accessibilityLabel("Audio input port selection")

                        // Built-in mic sub-options: orientation (data source) + polar pattern
                        if router.selectedPortIsBuiltInMic,
                           let dataSources = router.selectedPortDataSources,
                           !dataSources.isEmpty {
                            Picker("Mic Orientation", selection: Binding(
                                get: { router.selectedDataSourceId ?? "" },
                                set: { id in
                                    if !id.isEmpty { router.selectDataSource(id) }
                                }
                            )) {
                                Text("Default").tag("")
                                ForEach(dataSources) { ds in
                                    Text(ds.name).tag(ds.id)
                                }
                            }
                            .accessibilityLabel("Microphone orientation")

                            // Polar pattern sub-picker
                            if let selectedDs = dataSources.first(where: { $0.id == router.selectedDataSourceId }),
                               let patterns = selectedDs.polarPatterns,
                               !patterns.isEmpty {
                                Picker("Polar Pattern", selection: Binding(
                                    get: { router.selectedPolarPattern ?? "" },
                                    set: { pattern in
                                        if !pattern.isEmpty { router.selectPolarPattern(pattern) }
                                    }
                                )) {
                                    Text("Default").tag("")
                                    ForEach(patterns, id: \.self) { pattern in
                                        Text(polarPatternLabel(pattern)).tag(pattern)
                                    }
                                }
                                .accessibilityLabel("Microphone polar pattern")
                            }
                        }

                        // Mic processing mode: Standard vs Raw/Studio
                        Picker("Mic Mode", selection: Binding(
                            get: { router.micMode },
                            set: { router.selectMicMode($0) }
                        )) {
                            ForEach(IOSAudioRouter.MicMode.allCases) { mode in
                                Text(mode.rawValue).tag(mode)
                            }
                        }
                        .accessibilityLabel("Microphone processing mode")

                        // Voice-processing (VPIO) controls — only meaningful on a VPIO-capable
                        // config (mono + standard + non-A2DP). iOS bundles echo cancellation and
                        // noise suppression into one master switch (no per-stage toggle); AGC is
                        // the one sub-stage it lets us control independently.
                        if router.voiceProcessingAvailable {
                            Toggle("Voice Processing (AEC + noise suppression)", isOn: Binding(
                                get: { router.voiceProcessingEnabled },
                                set: { router.setVoiceProcessingEnabled($0) }
                            ))
                            .accessibilityLabel("Voice processing")
                            .accessibilityHint("Echo cancellation and noise suppression, bundled together by iOS.")

                            if router.voiceProcessingEnabled {
                                Toggle("Automatic Gain Control", isOn: Binding(
                                    get: { router.agcEnabled },
                                    set: { router.setAgcEnabled($0) }
                                ))
                                .accessibilityLabel("Automatic gain control")
                            }
                        }

                        if router.showsRawModeSpeakerWarning {
                            Label(
                                "Raw mode on speaker — echo risk (no AEC)",
                                systemImage: "exclamationmark.triangle.fill"
                            )
                            .foregroundStyle(.orange)
                            .font(.caption)
                            .accessibilityLabel("Warning: Raw mode with speaker output may cause echo")
                        }

                        if router.showsA2dpNoAecWarning {
                            Label(
                                "A2DP mode — no echo cancellation (hardware AEC unavailable)",
                                systemImage: "info.circle.fill"
                            )
                            .foregroundStyle(.blue)
                            .font(.caption)
                            .accessibilityLabel("Info: A2DP output mode does not support hardware echo cancellation")
                        }


                        // Capture channels: Mono vs Stereo
                        Picker("Channels", selection: Binding(
                            get: { router.captureChannels },
                            set: { router.selectCaptureChannels($0) }
                        )) {
                            ForEach(IOSAudioRouter.CaptureChannels.allCases) { ch in
                                Text(ch.rawValue).tag(ch)
                            }
                        }
                        .accessibilityLabel("Capture channel count")

                        // Bluetooth mode
                        Picker("Bluetooth Mode", selection: Binding(
                            get: { router.bluetoothMode },
                            set: { router.selectBluetoothMode($0) }
                        )) {
                            ForEach(IOSAudioRouter.BluetoothMode.allCases) { mode in
                                Text(mode.rawValue).tag(mode)
                            }
                        }
                        .accessibilityLabel("Bluetooth audio mode")

                        // Current output route (read-only)
                        if !router.outputRoutes.isEmpty {
                            ForEach(router.outputRoutes) { route in
                                HStack {
                                    Text(route.name)
                                    Spacer()
                                    Text(route.portType)
                                        .foregroundStyle(.secondary)
                                        .font(.caption)
                                }
                                .accessibilityLabel("Current output: \(route.name)")
                            }
                        } else {
                            Text("No output route")
                                .foregroundStyle(.secondary)
                        }

                        // AirPlay button
                        HStack {
                            Text("AirPlay")
                            Spacer()
                            RoutePickerButton()
                        }
                        .accessibilityLabel("AirPlay output selector")
                    }
                }

                // MARK: - Voice
                Section("Voice") {
                    Picker("Input Mode", selection: Binding(
                        get: { session.voiceState.inputMode },
                        set: { session.setInputMode($0) }
                    )) {
                        Text("Voice Activation").tag(VoiceCatInputMode.voiceActivation)
                        Text("Push to Talk").tag(VoiceCatInputMode.pushToTalk)
                        Text("Always On").tag(VoiceCatInputMode.alwaysOn)
                    }
                    .accessibilityLabel("Voice input mode")

                    if session.voiceState.inputMode == .voiceActivation {
                        VStack(alignment: .leading, spacing: 4) {
                            Text("VAD Threshold: \(String(format: "%.3f", session.voiceState.vadThreshold))")
                                .font(.caption)
                            Slider(
                                value: Binding(
                                    get: { Double(session.voiceState.vadThreshold) },
                                    set: { session.setVadThreshold(Float($0)) }
                                ),
                                in: 0.001...0.1, step: 0.001
                            )
                            .accessibilityLabel("Voice activation threshold")
                        }
                    }

                    VStack(alignment: .leading, spacing: 4) {
                        Text("Mic Volume: \(Int((session.voiceState.inputGain * 100).rounded()))%")
                            .font(.caption)
                        Slider(
                            value: Binding(
                                get: { Double(session.voiceState.inputGain) },
                                set: { session.setInputGain(Float($0)) }
                            ),
                            in: 0...4, step: 0.05
                        )
                        .accessibilityLabel("Microphone volume")
                        .accessibilityValue("\(Int((session.voiceState.inputGain * 100).rounded())) percent")
                    }

                    Toggle("Noise Reduction (RNNoise)", isOn: Binding(
                        get: { session.voiceState.inputNoiseReduction },
                        set: { session.setInputNoiseReduction($0) }
                    ))
                    .accessibilityLabel("Microphone noise reduction")
                    .accessibilityHint("Denoises your microphone signal for everyone listening.")
                }

                // MARK: - Notifications
                Section("Notifications") {
                    Toggle("Event sounds", isOn: $soundsEnabled)
                        .accessibilityLabel("Play event sounds")
                    if soundsEnabled {
                        VStack(alignment: .leading, spacing: 4) {
                            Text("Sound volume")
                                .font(.caption)
                            Slider(value: $soundsVolume, in: 0...1)
                                .accessibilityLabel("Sound volume")
                        }
                    }
                    Toggle("Speak events (text-to-speech)", isOn: $speechEnabled)
                        .accessibilityLabel("Speak events")
                        .accessibilityHint("Announces joins and leaves and reads message text aloud.")
                    Toggle("Your own voice-activity sounds", isOn: $selfTalkEnabled)
                        .accessibilityLabel("Voice activity sounds")
                    Toggle("Push-to-talk cue", isOn: $pttSoundEnabled)
                        .accessibilityLabel("Push to talk cue")
                }

                // MARK: - Admin
                if session.permissions.canAdminAccounts || session.permissions.isAdmin {
                    Section("Administration") {
                        NavigationLink("Manage Accounts") {
                            AccountsView(session: session)
                        }
                        .accessibilityLabel("Manage server accounts")
                    }
                }

                // MARK: - Server
                Section("Server") {
                    Button(role: .destructive) {
                        session.stopMicStream()
                        appState.disconnect()
                    } label: {
                        Label("Disconnect", systemImage: "phone.down")
                            .foregroundStyle(.red)
                    }
                    .accessibilityLabel("Disconnect from server")
                }

                // MARK: - About
                Section("About") {
                    Text(VoiceCatClient.versionString)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                        .accessibilityLabel("Version: \(VoiceCatClient.versionString)")
                }
            }
            .navigationTitle("Settings")
            .onAppear {
                router.refreshRoutes()
            }
        }
    }

    /// Human-readable label for AVAudioSession.PolarPattern raw values.
    private func polarPatternLabel(_ rawValue: String) -> String {
        switch rawValue {
        case AVAudioSession.PolarPattern.omnidirectional.rawValue: return "Omnidirectional"
        case AVAudioSession.PolarPattern.cardioid.rawValue: return "Cardioid"
        case AVAudioSession.PolarPattern.subcardioid.rawValue: return "Subcardioid"
        default: return rawValue
        }
    }
}

/// SwiftUI wrapper for AVRoutePickerView (AVKit's UIView for AirPlay route selection).
private struct RoutePickerButton: UIViewRepresentable {
    func makeUIView(context: Context) -> AVRoutePickerView {
        let view = AVRoutePickerView()
        view.tintColor = .systemBlue
        return view
    }

    func updateUIView(_ uiView: AVRoutePickerView, context: Context) {}
}
