//
//  PlayerControlsSettingsView.swift
//  Yattee
//
//  Main settings view for player controls customization.
//

import SwiftUI

/// Settings view for customizing player controls layout and presets.
struct PlayerControlsSettingsView: View {
    @Environment(\.appEnvironment) private var appEnvironment
    @State private var viewModel: PlayerControlsSettingsViewModel?

    var body: some View {
        Group {
            if let viewModel {
                PlayerControlsSettingsContent(viewModel: viewModel)
            } else {
                ProgressView()
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
        .navigationTitle(String(localized: "settings.playerControls.title"))
        #if os(iOS)
        .navigationBarTitleDisplayMode(.inline)
        #endif
        .task {
            if viewModel == nil, let appEnv = appEnvironment {
                let vm = PlayerControlsSettingsViewModel(
                    layoutService: appEnv.playerControlsLayoutService,
                    settingsManager: appEnv.settingsManager
                )
                viewModel = vm
                await vm.loadPresets()
            }
        }
    }
}

// MARK: - Content View

private struct PlayerControlsSettingsContent: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel

    // Local state for immediate UI updates
    @State private var style: ControlsStyle = .glass
    @State private var buttonSize: ButtonSize = .medium
    @State private var fontStyle: ControlsFontStyle = .system

    // Refresh trigger to force view update on navigation back
    @State private var refreshID = UUID()

    // Track active preset locally to ensure view updates
    @State private var trackedActivePresetName: String = "Default"

    // Create preset sheet state (kept at parent level for stability across refreshes)
    @State private var showCreatePresetSheet = false
    @State private var pendingPresetCreation: PendingPresetCreation?

    private struct PendingPresetCreation: Equatable {
        let name: String
        let basePresetID: UUID?
    }

    /// Layout with local settings override for immediate preview updates
    private var previewLayout: PlayerControlsLayout {
        var layout = viewModel.currentLayout
        layout.globalSettings.style = style
        layout.globalSettings.buttonSize = buttonSize
        layout.globalSettings.fontStyle = fontStyle
        return layout
    }

    var body: some View {
        Form {
            // The phone-shaped preview and comments pill don't apply to the macOS player.
            #if os(iOS)
            PreviewSection(viewModel: viewModel, layout: previewLayout)
            #endif
            PresetSection(
                viewModel: viewModel,
                trackedPresetName: $trackedActivePresetName,
                showCreateSheet: $showCreatePresetSheet
            )
            AppearanceSection(
                viewModel: viewModel,
                style: $style,
                buttonSize: $buttonSize,
                fontStyle: $fontStyle
            )
            LayoutSectionsSection(viewModel: viewModel)
            #if os(iOS)
            CommentsPillSection(viewModel: viewModel)
            GesturesSectionsSection(viewModel: viewModel)
            #endif
            SystemControlsSection(viewModel: viewModel)
            VolumeSection(viewModel: viewModel)
        }
        #if os(macOS)
        .formStyle(.grouped)
        #endif
        .opaqueSettingsFormBackground()
        .id(refreshID)
        .alert(
            String(localized: "settings.playerControls.error"),
            isPresented: .constant(viewModel.error != nil)
        ) {
            Button(String(localized: "settings.playerControls.ok")) {
                viewModel.clearError()
            }
        } message: {
            if let error = viewModel.error {
                Text(error)
            }
        }
        .sheet(isPresented: $showCreatePresetSheet) {
            PresetEditorView(
                mode: .create(
                    baseLayouts: viewModel.presets,
                    activePreset: viewModel.activePreset
                ),
                onSave: { name, basePresetID in
                    pendingPresetCreation = PendingPresetCreation(name: name, basePresetID: basePresetID)
                }
            )
        }
        .task(id: pendingPresetCreation) {
            guard let creation = pendingPresetCreation else { return }
            let basePreset = creation.basePresetID.flatMap { id in
                viewModel.presets.first { $0.id == id }
            }
            await viewModel.createPreset(name: creation.name, basedOn: basePreset)
            pendingPresetCreation = nil
            trackedActivePresetName = viewModel.activePreset?.name ?? "Default"
            NotificationCenter.default.post(name: .presetSelectionDidChange, object: viewModel.activePreset?.name)
        }
        .onAppear {
            style = viewModel.currentLayout.globalSettings.style
            buttonSize = viewModel.currentLayout.globalSettings.buttonSize
            fontStyle = viewModel.currentLayout.globalSettings.fontStyle
            trackedActivePresetName = viewModel.activePreset?.name ?? "Default"
            // Force refresh on every appear to pick up changes from sub-editors
            refreshID = UUID()
        }
        .onChange(of: viewModel.activePreset?.id) { _, _ in
            // Sync when preset changes
            style = viewModel.currentLayout.globalSettings.style
            buttonSize = viewModel.currentLayout.globalSettings.buttonSize
            fontStyle = viewModel.currentLayout.globalSettings.fontStyle
            trackedActivePresetName = viewModel.activePreset?.name ?? "Default"
        }
        .onChange(of: viewModel.activePreset?.name) { _, newName in
            // Also track name changes (for initial load)
            trackedActivePresetName = newName ?? "Default"
        }
        .onReceive(NotificationCenter.default.publisher(for: .presetSelectionDidChange)) { notification in
            if let name = notification.object as? String {
                trackedActivePresetName = name
            }
        }
    }
}

// MARK: - Preview Section

private struct PreviewSection: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel
    let layout: PlayerControlsLayout

    var body: some View {
        Section {
            PlayerControlsPreviewView(
                layout: layout,
                isLandscape: viewModel.isPreviewingLandscape
            )
            .frame(height: 200)
            .listRowInsets(EdgeInsets())

            Picker(
                String(localized: "settings.playerControls.previewOrientation"),
                selection: $viewModel.isPreviewingLandscape
            ) {
                Text(String(localized: "settings.playerControls.portrait"))
                    .tag(false)
                Text(String(localized: "settings.playerControls.landscape"))
                    .tag(true)
            }
            .pickerStyle(.segmented)
            .padding(.horizontal)
            .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
        }
    }
}

// MARK: - Preset Section

private struct PresetSection: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel
    @Binding var trackedPresetName: String
    @Binding var showCreateSheet: Bool

    private var isBuiltInPreset: Bool {
        viewModel.activePreset?.isBuiltIn == true
    }

    var body: some View {
        Section {
            NavigationLink {
                PresetSelectorView(viewModel: viewModel, onPresetSelected: { name in
                    trackedPresetName = name
                })
            } label: {
                HStack {
                    Text(String(localized: "settings.playerControls.activePreset"))
                    Spacer()
                    Text(trackedPresetName)
                        .foregroundStyle(.secondary)
                }
            }

            if isBuiltInPreset {
                Button {
                    showCreateSheet = true
                } label: {
                    Text(String(localized: "settings.playerControls.newPreset"))
                }
            }
        } footer: {
            if isBuiltInPreset {
                Text(String(localized: "settings.playerControls.builtInPresetHint"))
            }
        }
    }
}

// MARK: - Appearance Section

private struct AppearanceSection: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel
    @Binding var style: ControlsStyle
    @Binding var buttonSize: ButtonSize
    @Binding var fontStyle: ControlsFontStyle

    var body: some View {
        Section {
            // The macOS bar draws its own glass capsule; the per-button style has no effect there.
            #if os(iOS)
            Picker(
                String(localized: "settings.playerControls.style"),
                selection: $style
            ) {
                ForEach(ControlsStyle.allCases, id: \.self) { styleOption in
                    Text(styleOption.displayName).tag(styleOption)
                }
            }
            .disabled(!viewModel.canEditActivePreset)
            .onChange(of: style) { _, newStyle in
                guard newStyle != viewModel.currentLayout.globalSettings.style else { return }
                viewModel.updateGlobalSettingsSync { $0.style = newStyle }
            }
            #endif

            Picker(
                String(localized: "settings.playerControls.buttonSize"),
                selection: $buttonSize
            ) {
                ForEach(ButtonSize.allCases, id: \.self) { size in
                    Text(size.displayName).tag(size)
                }
            }
            .disabled(!viewModel.canEditActivePreset)
            .onChange(of: buttonSize) { _, newSize in
                guard newSize != viewModel.currentLayout.globalSettings.buttonSize else { return }
                viewModel.updateGlobalSettingsSync { $0.buttonSize = newSize }
            }

            Picker(
                String(localized: "settings.playerControls.fontStyle"),
                selection: $fontStyle
            ) {
                ForEach(ControlsFontStyle.allCases, id: \.self) { fontStyleOption in
                    Text(fontStyleOption.displayName).tag(fontStyleOption)
                }
            }
            .disabled(!viewModel.canEditActivePreset)
            .onChange(of: fontStyle) { _, newFontStyle in
                guard newFontStyle != viewModel.currentLayout.globalSettings.fontStyle else { return }
                viewModel.updateGlobalSettingsSync { $0.fontStyle = newFontStyle }
            }
        } header: {
            Text(String(localized: "settings.playerControls.appearance"))
        }
    }
}

// MARK: - Layout Sections Section

private struct LayoutSectionsSection: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel

    var body: some View {
        Section {
            NavigationLink {
                SectionEditorView(
                    sectionType: .top,
                    viewModel: viewModel
                )
            } label: {
                HStack {
                    Label(
                        String(localized: "settings.playerControls.topButtons"),
                        systemImage: "rectangle.topthird.inset.filled"
                    )
                    Spacer()
                    Text("\(viewModel.currentLayout.topSection.buttons.count)")
                        .foregroundStyle(.secondary)
                }
            }
            .disabled(!viewModel.canEditActivePreset)

            NavigationLink {
                CenterControlsSettingsView(viewModel: viewModel)
            } label: {
                #if os(macOS)
                Label(
                    String(localized: "settings.playerControls.seekDurations", defaultValue: "Seek Durations"),
                    systemImage: "arrow.trianglehead.clockwise"
                )
                #else
                Label(
                    String(localized: "settings.playerControls.centerControls"),
                    systemImage: "play.circle"
                )
                #endif
            }
            .disabled(!viewModel.canEditActivePreset)

            NavigationLink {
                ProgressBarSettingsView(viewModel: viewModel)
            } label: {
                Label(
                    String(localized: "settings.playerControls.progressBar"),
                    systemImage: "slider.horizontal.below.rectangle"
                )
            }
            .disabled(!viewModel.canEditActivePreset)

            NavigationLink {
                SectionEditorView(
                    sectionType: .bottom,
                    viewModel: viewModel
                )
            } label: {
                HStack {
                    #if os(macOS)
                    Label(
                        String(localized: "settings.playerControls.controlBar", defaultValue: "Control Bar"),
                        systemImage: "rectangle.bottomthird.inset.filled"
                    )
                    #else
                    Label(
                        String(localized: "settings.playerControls.bottomButtons"),
                        systemImage: "rectangle.bottomthird.inset.filled"
                    )
                    #endif
                    Spacer()
                    Text("\(viewModel.currentLayout.bottomSection.buttons.count)")
                        .foregroundStyle(.secondary)
                }
            }
            .disabled(!viewModel.canEditActivePreset)

            // The player pill only exists in the iOS player.
            #if os(iOS)
            NavigationLink {
                PlayerPillEditorView(viewModel: viewModel)
            } label: {
                HStack {
                    Label(
                        String(localized: "settings.playerControls.playerPill"),
                        systemImage: "capsule"
                    )
                    Spacer()
                    Text("\(viewModel.playerPillSettings.buttons.count)")
                        .foregroundStyle(.secondary)
                }
            }
            .disabled(!viewModel.canEditActivePreset)
            #endif

            NavigationLink {
                MiniPlayerEditorView(viewModel: viewModel)
            } label: {
                Label(
                    String(localized: "settings.playerControls.miniPlayer"),
                    systemImage: "pip"
                )
            }
            .disabled(!viewModel.canEditActivePreset)
        } header: {
            Text(String(localized: "settings.playerControls.layoutSections"))
        } footer: {
            if !viewModel.canEditActivePreset {
                Text(String(localized: "settings.playerControls.duplicateToEdit"))
            }
        }
    }
}

// MARK: - Comments Pill Section

private struct CommentsPillSection: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel

    // Local state for immediate UI updates
    @State private var commentsPillMode: CommentsPillMode = .pill

    var body: some View {
        Section {
            Picker(
                String(localized: "commentsPill.mode.title"),
                selection: $commentsPillMode
            ) {
                ForEach(CommentsPillMode.allCases, id: \.self) { mode in
                    Text(mode.displayName).tag(mode)
                }
            }
            .disabled(!viewModel.canEditActivePreset)
            .onChange(of: commentsPillMode) { _, newValue in
                guard newValue != viewModel.commentsPillMode else { return }
                viewModel.syncCommentsPillMode(newValue)
            }
        }
        .onAppear {
            commentsPillMode = viewModel.commentsPillMode
        }
        .onChange(of: viewModel.activePreset?.id) { _, _ in
            commentsPillMode = viewModel.commentsPillMode
        }
    }
}

// MARK: - Gestures Sections Section (iOS only)

#if os(iOS)
private struct GesturesSectionsSection: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel

    var body: some View {
        Section {
            NavigationLink {
                TapGesturesSettingsView(viewModel: viewModel)
            } label: {
                HStack {
                    Label(
                        String(localized: "gestures.tap.title", defaultValue: "Tap Gestures"),
                        systemImage: "hand.tap"
                    )
                    Spacer()
                    if viewModel.gesturesSettings.tapGestures.isEnabled {
                        Text(viewModel.gesturesSettings.tapGestures.layout.layoutDescription)
                            .foregroundStyle(.secondary)
                    } else {
                        Text(String(localized: "common.disabled", defaultValue: "Disabled"))
                            .foregroundStyle(.tertiary)
                    }
                }
            }
            .disabled(!viewModel.canEditActivePreset)

            NavigationLink {
                SeekGestureSettingsView(viewModel: viewModel)
            } label: {
                HStack {
                    Label(
                        String(localized: "gestures.seek.title", defaultValue: "Seek Gesture"),
                        systemImage: "hand.draw"
                    )
                    Spacer()
                    if viewModel.gesturesSettings.seekGesture.isEnabled {
                        Text(viewModel.gesturesSettings.seekGesture.sensitivity.displayName)
                            .foregroundStyle(.secondary)
                    } else {
                        Text(String(localized: "common.disabled", defaultValue: "Disabled"))
                            .foregroundStyle(.tertiary)
                    }
                }
            }
            .disabled(!viewModel.canEditActivePreset)

            NavigationLink {
                PanscanGestureSettingsView(viewModel: viewModel)
            } label: {
                HStack {
                    Label(
                        String(localized: "gestures.panscan.title", defaultValue: "Panscan Gesture"),
                        systemImage: "hand.pinch"
                    )
                    Spacer()
                    if viewModel.gesturesSettings.panscanGesture.isEnabled {
                        if viewModel.gesturesSettings.panscanGesture.snapToEnds {
                            Text(String(localized: "gestures.panscan.snap", defaultValue: "Snap"))
                                .foregroundStyle(.secondary)
                        } else {
                            Text(String(localized: "gestures.panscan.freeZoom", defaultValue: "Free Zoom"))
                                .foregroundStyle(.secondary)
                        }
                    } else {
                        Text(String(localized: "common.disabled", defaultValue: "Disabled"))
                            .foregroundStyle(.tertiary)
                    }
                }
            }
            .disabled(!viewModel.canEditActivePreset)
        } header: {
            Text(String(localized: "gestures.section.title", defaultValue: "Gestures"))
        } footer: {
            Text(String(localized: "gestures.section.footer", defaultValue: "Control playback with gestures when player controls are hidden."))
        }
    }
}
#endif

// MARK: - System Controls Section

private struct SystemControlsSection: View {
    @Environment(\.appEnvironment) private var appEnvironment
    @Bindable var viewModel: PlayerControlsSettingsViewModel

    // Local state for immediate UI updates
    @State private var systemControlsMode: SystemControlsMode = .seek
    @State private var systemControlsSeekDuration: SystemControlsSeekDuration = .tenSeconds

    var body: some View {
        Section {
            Picker(
                String(localized: "settings.playback.systemControls.mode"),
                selection: $systemControlsMode
            ) {
                ForEach(SystemControlsMode.allCases, id: \.self) { mode in
                    Text(mode.displayName).tag(mode)
                }
            }
            .disabled(!viewModel.canEditActivePreset)
            .onChange(of: systemControlsMode) { _, newMode in
                guard newMode != viewModel.systemControlsMode else { return }
                viewModel.updateSystemControlsModeSync(newMode)
                appEnvironment?.playerService.reconfigureSystemControls(
                    mode: newMode,
                    duration: viewModel.systemControlsSeekDuration
                )
            }

            if systemControlsMode == .seek {
                Picker(
                    String(localized: "settings.playback.systemControls.seekDuration"),
                    selection: $systemControlsSeekDuration
                ) {
                    ForEach(SystemControlsSeekDuration.allCases, id: \.self) { duration in
                        Text(duration.displayName).tag(duration)
                    }
                }
                .disabled(!viewModel.canEditActivePreset)
                .onChange(of: systemControlsSeekDuration) { _, newDuration in
                    guard newDuration != viewModel.systemControlsSeekDuration else { return }
                    viewModel.updateSystemControlsSeekDurationSync(newDuration)
                    appEnvironment?.playerService.reconfigureSystemControls(
                        mode: viewModel.systemControlsMode,
                        duration: newDuration
                    )
                }
            }
        } header: {
            Text(String(localized: "settings.playback.systemControls.header"))
        } footer: {
            if systemControlsMode == .seek {
                Text(String(localized: "settings.playback.systemControls.seek.footer"))
            } else {
                Text(String(localized: "settings.playback.systemControls.skipTrack.footer"))
            }
        }
        .onAppear {
            syncLocalState()
        }
        .onChange(of: viewModel.activePreset?.id) { _, _ in
            syncLocalState()
        }
    }

    private func syncLocalState() {
        systemControlsMode = viewModel.systemControlsMode
        systemControlsSeekDuration = viewModel.systemControlsSeekDuration
    }
}

// MARK: - Volume Section

private struct VolumeSection: View {
    @Environment(\.appEnvironment) private var appEnvironment
    @Bindable var viewModel: PlayerControlsSettingsViewModel

    // Local state for immediate UI updates
    @State private var volumeMode: VolumeMode = .mpv

    var body: some View {
        Section {
            Picker(
                String(localized: "settings.playback.volume.mode"),
                selection: $volumeMode
            ) {
                ForEach(VolumeMode.allCases, id: \.self) { mode in
                    Text(mode.displayName).tag(mode)
                }
            }
            .disabled(!viewModel.canEditActivePreset)
            .onChange(of: volumeMode) { _, newMode in
                guard newMode != viewModel.volumeMode else { return }
                viewModel.updateVolumeModeSync(newMode)
                if newMode == .system {
                    // Set MPV to 100% when switching to system mode
                    appEnvironment?.playerService.currentBackend?.volume = 1.0
                    appEnvironment?.playerService.state.volume = 1.0
                }
                // Broadcast the mode change to remote devices
                appEnvironment?.remoteControlCoordinator.broadcastStateUpdate()
            }
        } header: {
            Text(String(localized: "settings.playback.volume.header"))
        } footer: {
            if volumeMode == .mpv {
                Text(String(localized: "settings.playback.volume.mpv.footer"))
            } else {
                Text(String(localized: "settings.playback.volume.system.footer"))
            }
        }
        .onAppear {
            syncLocalState()
        }
        .onChange(of: viewModel.activePreset?.id) { _, _ in
            syncLocalState()
        }
    }

    private func syncLocalState() {
        volumeMode = viewModel.volumeMode
    }
}

// MARK: - Preview

#Preview {
    NavigationStack {
        PlayerControlsSettingsView()
    }
    .appEnvironment(.preview)
}
