//
//  PresetSelectorView.swift
//  Yattee
//
//  View for selecting and managing player controls presets.
//

import SwiftUI
#if !os(tvOS)
import UniformTypeIdentifiers
#endif

// MARK: - Export File Wrapper

#if !os(tvOS)
private struct ExportFile: Identifiable {
    let id = UUID()
    let url: URL
}
#endif

/// Pending preset creation request
private struct PendingPresetCreation: Equatable {
    let name: String
    let basePresetID: UUID?
}

/// Pending preset rename request
private struct PendingPresetRename: Equatable {
    let presetID: UUID
    let newName: String
}

/// Notification posted when a preset is selected in PresetSelectorView
extension Notification.Name {
    static let presetSelectionDidChange = Notification.Name("presetSelectionDidChange")
}

/// View for selecting and managing player controls layout presets.
struct PresetSelectorView: View {
    @Bindable var viewModel: PlayerControlsSettingsViewModel
    var onPresetSelected: ((String) -> Void)?

    @State private var showCreateSheet = false
    @State private var presetToRename: LayoutPreset?
    @State private var pendingCreation: PendingPresetCreation?
    @State private var pendingRename: PendingPresetRename?
    @State private var listRefreshID = UUID()

    // Track active preset ID locally to force view updates
    @State private var trackedActivePresetID: UUID?

    // Import/Export state
    #if !os(tvOS)
    @State private var showingImportPicker = false
    @State private var isImporting = false
    @State private var importError: String?
    @State private var showingImportError = false
    @State private var importedPresetName: String?
    @State private var showingImportSuccess = false
    @State private var exportFile: ExportFile?
    #endif

    var body: some View {
        presetList
            .opaqueSettingsFormBackground()
            .navigationTitle(String(localized: "settings.playerControls.presets"))
            #if os(iOS)
            .navigationBarTitleDisplayMode(.inline)
            #endif
            .toolbar { toolbarContent }
            .sheet(isPresented: $showCreateSheet) { createPresetSheet }
            .sheet(item: $presetToRename) { preset in renamePresetSheet(preset) }
            #if os(iOS)
            .sheet(isPresented: $showingImportPicker) { importPickerSheet }
            .sheet(item: $exportFile) { file in ShareSheet(items: [file.url]) }
            #endif
            #if !os(tvOS)
            .alert(
                String(localized: "settings.playerControls.import.error.title"),
                isPresented: $showingImportError
            ) {
                Button(String(localized: "settings.playerControls.ok")) {}
            } message: {
                if let error = importError {
                    Text(error)
                }
            }
            .alert(
                String(localized: "settings.playerControls.import.success.title"),
                isPresented: $showingImportSuccess
            ) {
                Button(String(localized: "settings.playerControls.ok")) {}
            } message: {
                if let name = importedPresetName {
                    Text(String(localized: "settings.playerControls.import.success.message \(name)"))
                }
            }
            #endif
            .task(id: pendingCreation) {
                guard let creation = pendingCreation else { return }
                let basePreset = creation.basePresetID.flatMap { id in
                    viewModel.presets.first { $0.id == id }
                }
                await viewModel.createPreset(name: creation.name, basedOn: basePreset)
                pendingCreation = nil
                // Force view update by updating local tracked state
                trackedActivePresetID = viewModel.activePreset?.id
                listRefreshID = UUID()
                // Notify parent of selection change
                if let name = viewModel.activePreset?.name {
                    onPresetSelected?(name)
                    NotificationCenter.default.post(name: .presetSelectionDidChange, object: name)
                }
            }
            .task(id: pendingRename) {
                guard let rename = pendingRename else { return }
                if let preset = viewModel.presets.first(where: { $0.id == rename.presetID }) {
                    await viewModel.renamePreset(preset, to: rename.newName)
                }
                pendingRename = nil
                listRefreshID = UUID()
            }
            .onAppear {
                trackedActivePresetID = viewModel.activePreset?.id
            }
    }

    // MARK: - View Components

    private var presetList: some View {
        List {
            builtInPresetsSection
            customPresetsSection
        }
        .id(listRefreshID)
    }

    private var builtInPresetsSection: some View {
        Section {
            ForEach(viewModel.builtInPresets) { preset in
                PresetRow(
                    preset: preset,
                    isActive: preset.id == trackedActivePresetID,
                    onSelect: {
                        viewModel.selectPreset(preset)
                        trackedActivePresetID = preset.id
                        onPresetSelected?(preset.name)
                        NotificationCenter.default.post(name: .presetSelectionDidChange, object: preset.name)
                    }
                )
            }
        } header: {
            Text(String(localized: "settings.playerControls.builtInPresets"))
        }
    }

    @ViewBuilder
    private var customPresetsSection: some View {
        if !viewModel.customPresets.isEmpty {
            Section {
                ForEach(viewModel.customPresets) { preset in
                    customPresetRow(preset)
                }
            } header: {
                Text(String(localized: "settings.playerControls.customPresets"))
            }
        }
    }

    private func customPresetRow(_ preset: LayoutPreset) -> some View {
        PresetRow(
            preset: preset,
            isActive: preset.id == trackedActivePresetID,
            onSelect: {
                viewModel.selectPreset(preset)
                trackedActivePresetID = preset.id
                onPresetSelected?(preset.name)
                NotificationCenter.default.post(name: .presetSelectionDidChange, object: preset.name)
            },
            onRename: { presetToRename = preset },
            onExport: {
                #if !os(tvOS)
                exportPreset(preset)
                #endif
            },
            onDelete: {
                Task { await viewModel.deletePreset(preset) }
            },
            canDelete: preset.id != trackedActivePresetID
        )
    }

    @ToolbarContentBuilder
    private var toolbarContent: some ToolbarContent {
        #if !os(tvOS)
        ToolbarItem(placement: .primaryAction) {
            Menu {
                Button {
                    showCreateSheet = true
                } label: {
                    Label(
                        String(localized: "settings.playerControls.newPreset"),
                        systemImage: "plus"
                    )
                }

                Divider()

                Button {
                    showImportPicker()
                } label: {
                    Label(
                        String(localized: "settings.playerControls.importPreset"),
                        systemImage: "square.and.arrow.down"
                    )
                }
                .disabled(isImporting)
            } label: {
                Label(
                    String(localized: "settings.playerControls.newPreset"),
                    systemImage: "plus"
                )
            }
        }
        #else
        ToolbarItem(placement: .primaryAction) {
            Button {
                showCreateSheet = true
            } label: {
                Label(
                    String(localized: "settings.playerControls.newPreset"),
                    systemImage: "plus"
                )
            }
        }
        #endif
    }

    private var createPresetSheet: some View {
        PresetEditorView(
            mode: .create(
                baseLayouts: viewModel.presets,
                activePreset: viewModel.activePreset
            ),
            onSave: { name, basePresetID in
                pendingCreation = PendingPresetCreation(name: name, basePresetID: basePresetID)
            }
        )
    }

    private func renamePresetSheet(_ preset: LayoutPreset) -> some View {
        let presetID = preset.id
        return PresetEditorView(
            mode: .rename(currentName: preset.name),
            onSave: { name, _ in
                pendingRename = PendingPresetRename(presetID: presetID, newName: name)
            }
        )
    }

    #if os(iOS)
    private var importPickerSheet: some View {
        PresetFilePickerView { url in
            handleImportedFile(url)
        }
    }
    #endif

    // MARK: - Import/Export Actions

    #if !os(tvOS)
    private func showImportPicker() {
        #if os(iOS)
        showingImportPicker = true
        #elseif os(macOS)
        showMacOSImportPanel()
        #endif
    }

    #if os(macOS)
    private func showMacOSImportPanel() {
        let panel = NSOpenPanel()
        panel.allowedContentTypes = [.json]
        panel.canChooseFiles = true
        panel.canChooseDirectories = false
        panel.allowsMultipleSelection = false
        panel.message = String(localized: "settings.playerControls.import.panel.message")

        if panel.runModal() == .OK, let url = panel.url {
            handleImportedFile(url)
        }
    }
    #endif

    private func handleImportedFile(_ url: URL) {
        isImporting = true

        Task {
            do {
                let presetName = try await viewModel.importPreset(from: url)
                await MainActor.run {
                    isImporting = false
                    importedPresetName = presetName
                    showingImportSuccess = true
                }
            } catch {
                await MainActor.run {
                    isImporting = false
                    importError = error.localizedDescription
                    showingImportError = true
                }
            }
        }
    }

    private func exportPreset(_ preset: LayoutPreset) {
        guard let url = viewModel.exportPreset(preset) else { return }

        #if os(iOS)
        exportFile = ExportFile(url: url)
        #elseif os(macOS)
        showMacOSSavePanel(url: url, preset: preset)
        #endif
    }

    #if os(macOS)
    private func showMacOSSavePanel(url: URL, preset: LayoutPreset) {
        let panel = NSSavePanel()
        panel.nameFieldStringValue = PlayerControlsPresetExportImport.generateExportFilename(for: preset)
        panel.allowedContentTypes = [.json]

        if panel.runModal() == .OK, let saveURL = panel.url {
            do {
                // Remove existing file if it exists (NSSavePanel asks for confirmation)
                if FileManager.default.fileExists(atPath: saveURL.path) {
                    try FileManager.default.removeItem(at: saveURL)
                }
                try FileManager.default.copyItem(at: url, to: saveURL)
            } catch {
                LoggingService.shared.error("Failed to save preset file: \(error.localizedDescription)")
            }
        }
    }
    #endif
    #endif
}

// MARK: - Preset Row

private struct PresetRow: View {
    let preset: LayoutPreset
    let isActive: Bool
    let onSelect: () -> Void
    var onRename: (() -> Void)? = nil
    var onExport: (() -> Void)? = nil
    var onDelete: (() -> Void)? = nil
    var canDelete: Bool = true

    var body: some View {
        Button(action: onSelect) {
            HStack {
                VStack(alignment: .leading, spacing: 4) {
                    Text(preset.name)
                        .foregroundStyle(.primary)

                    if preset.isBuiltIn {
                        Text(String(localized: "settings.playerControls.builtIn"))
                            .font(.caption)
                            .foregroundStyle(.secondary)
                    }
                }

                Spacer()

                if isActive {
                    Image(systemName: "checkmark")
                        .foregroundStyle(.tint)
                }
            }
            .contentShape(Rectangle())
        }
        .buttonStyle(.plain)
        #if os(iOS)
        .swipeActions(edge: .trailing, allowsFullSwipe: false) {
            if let onDelete, !preset.isBuiltIn, canDelete {
                Button(role: .destructive) {
                    onDelete()
                } label: {
                    Label(
                        String(localized: "settings.playerControls.delete"),
                        systemImage: "trash"
                    )
                }
            }

            if let onRename, !preset.isBuiltIn {
                Button {
                    onRename()
                } label: {
                    Label(
                        String(localized: "settings.playerControls.rename"),
                        systemImage: "pencil"
                    )
                }
                .tint(.orange)
            }

            if let onExport, !preset.isBuiltIn {
                Button {
                    onExport()
                } label: {
                    Label(
                        String(localized: "settings.playerControls.exportPreset"),
                        systemImage: "square.and.arrow.up"
                    )
                }
                .tint(.blue)
            }
        }
        #endif
        .contextMenu {
            if let onRename, !preset.isBuiltIn {
                Button {
                    onRename()
                } label: {
                    Label(
                        String(localized: "settings.playerControls.rename"),
                        systemImage: "pencil"
                    )
                }
            }

            if let onExport, !preset.isBuiltIn {
                Button {
                    onExport()
                } label: {
                    Label(
                        String(localized: "settings.playerControls.exportPreset"),
                        systemImage: "square.and.arrow.up"
                    )
                }
            }

            if let onDelete, !preset.isBuiltIn, canDelete {
                Divider()
                Button(role: .destructive) {
                    onDelete()
                } label: {
                    Label(
                        String(localized: "settings.playerControls.delete"),
                        systemImage: "trash"
                    )
                }
            }
        }
    }
}

// MARK: - File Picker (iOS)

#if os(iOS)
private struct PresetFilePickerView: UIViewControllerRepresentable {
    let onSelect: (URL) -> Void

    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.json])
        picker.delegate = context.coordinator
        picker.allowsMultipleSelection = false
        return picker
    }

    func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(onSelect: onSelect)
    }

    final class Coordinator: NSObject, UIDocumentPickerDelegate {
        let onSelect: (URL) -> Void

        init(onSelect: @escaping (URL) -> Void) {
            self.onSelect = onSelect
        }

        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            guard let url = urls.first else { return }
            onSelect(url)
        }
    }
}
#endif

// MARK: - Preview

#Preview {
    NavigationStack {
        PresetSelectorView(
            viewModel: PlayerControlsSettingsViewModel(
                layoutService: PlayerControlsLayoutService(),
                settingsManager: SettingsManager()
            )
        )
    }
}
