import SwiftUI
import UniformTypeIdentifiers

// MARK: - iOS Main View

/// The main content view for the iOS app, assembling the part selector, sheet music,
/// legend, and transport bar. Manages file import/export and audio engine coordination.
struct MainView_iOS: View {
    @EnvironmentObject var appState: AppState_iOS
    @StateObject private var playbackState = PlaybackState()
    @StateObject private var audioEngine = AudioEngine()
    @State private var selection: Selection = .none
    @State private var playbackMeasure: Int = -1
    @State private var playbackBeatFraction: Double = 0.0

    // Presentation states
    @State private var showingDocumentPicker: DocumentPickerType?
    @State private var showingSettings = false
    @State private var showingShareSheet = false
    @State private var shareURL: URL?

    // Export state
    @State private var isExporting = false

    private var song: Song? {
        appState.currentSong
    }

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                if let song = song {
                    // Part selector bar
                    PartSelectorBar_iOS(
                        playbackState: playbackState,
                        partNames: song.partNames
                    )

                    Divider()

                    // Legend bar
                    LegendBar_iOS(
                        parts: song.parts,
                        recordedParts: playbackState.recordedParts
                    )

                    Divider()

                    // Sheet music (takes all remaining space)
                    SheetMusicViewContainer_iOS(
                        song: song,
                        selection: $selection,
                        playbackMeasure: $playbackMeasure,
                        playbackBeatFraction: $playbackBeatFraction
                    )

                    // Transport bar at bottom
                    TransportBar_iOS(
                        playbackState: playbackState,
                        partNames: song.partNames,
                        onPlay: { startPlayback() },
                        onStop: { stopPlayback() },
                        onRecord: { startRecording() },
                        onStopRecording: { stopPlayback() }
                    )
                } else {
                    // Empty state
                    Spacer()
                    VStack(spacing: 16) {
                        Image(systemName: "music.note.list")
                            .font(.system(size: 56))
                            .foregroundColor(.secondary)
                        Text("Acapella")
                            .font(.largeTitle)
                            .fontWeight(.bold)
                        Text("Import a song file to start\npracticing multipart harmony")
                            .font(.body)
                            .foregroundColor(.secondary)
                            .multilineTextAlignment(.center)

                        Button(action: { showingDocumentPicker = .song }) {
                            Label("Import Song", systemImage: "doc.badge.plus")
                                .font(.headline)
                        }
                        .buttonStyle(.borderedProminent)
                        .padding(.top, 8)
                    }
                    Spacer()
                }
            }
            .navigationTitle(song?.title ?? "Acapella")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Menu {
                        Button(action: { showingDocumentPicker = .song }) {
                            Label("Import Song...", systemImage: "doc.badge.plus")
                        }
                        Button(action: { showingDocumentPicker = .bundle }) {
                            Label("Import Bundle...", systemImage: "folder.badge.plus")
                        }

                        if song != nil {
                            Divider()

                            if appState.hasRecordedAudio {
                                Button(action: { saveBundleAndShare() }) {
                                    Label("Save Bundle", systemImage: "square.and.arrow.down")
                                }
                                Button(action: { exportFinalMix() }) {
                                    Label("Export Final Mix", systemImage: "waveform")
                                }
                                Button(role: .destructive, action: { appState.closeAudio() }) {
                                    Label("Clear Recordings", systemImage: "trash")
                                }
                            }

                            Divider()

                            Button(role: .destructive, action: {
                                stopPlayback()
                                appState.closeSong()
                            }) {
                                Label("Close Song", systemImage: "xmark.circle")
                            }
                        }
                    } label: {
                        Image(systemName: "line.3.horizontal")
                    }
                }

                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: { showingSettings = true }) {
                        Image(systemName: "gearshape")
                    }
                }
            }
        }
        .onAppear {
            setupAudioCallbacks()
        }
        .onChange(of: selection) { newValue in
            playbackState.selection = newValue
        }
        .onChange(of: appState.currentSong) { newSong in
            audioEngine.stopPlayback()
            playbackState.mode = .stopped
            playbackMeasure = -1
            playbackBeatFraction = 0.0

            if let newSong = newSong {
                playbackState.defaultTempo = newSong.defaultTempo
                playbackState.tempo = newSong.defaultTempo
                playbackState.currentPart = "All"
                playbackState.recordedParts = []
                selection = .none
                audioEngine.setup(song: newSong)
            }
        }
        .onChange(of: playbackState.tempo) { newTempo in
            audioEngine.updateTempo(newTempo)
        }
        // Document picker (song or bundle)
        .sheet(item: $showingDocumentPicker) { pickerType in
            DocumentPicker_iOS(type: pickerType) { url in
                // Detect if the picked file is inside a .acapella bundle
                let parent = url.deletingLastPathComponent()
                if parent.pathExtension == "acapella" {
                    appState.loadBundle(from: parent, pickedFileURL: url)
                } else {
                    appState.loadSong(from: url)
                }
            }
        }
        // Settings sheet
        .sheet(isPresented: $showingSettings) {
            SettingsView_iOS(appState: appState)
        }
        // Share sheet for export
        .sheet(isPresented: $showingShareSheet) {
            if let url = shareURL {
                ShareSheet_iOS(activityItems: [url])
            }
        }
    }

    // MARK: - Audio integration

    private func setupAudioCallbacks() {
        audioEngine.onPositionUpdate = { measure, fraction in
            playbackMeasure = measure
            playbackBeatFraction = fraction
        }
        audioEngine.onPlaybackStopped = {
            playbackState.mode = .stopped
            playbackMeasure = -1
            playbackBeatFraction = 0.0
        }
        audioEngine.onRecordingComplete = { partName, url, startMeasure in
            playbackState.markPartRecorded(partName)
            appState.originalAudioURLs[partName] = url
            appState.recordedAudioURLs[partName] = url
            appState.recordingStartMeasures[partName] = startMeasure
            appState.hasRecordedAudio = true
            // Run pitch correction on background queue if enabled
            appState.applyPitchCorrection(partName: partName)
        }
    }

    private func effectivePlaybackSelection() -> Selection {
        if selection.hasSelection {
            return selection
        } else if selection.cursor >= 0, let song = song {
            var sel = Selection()
            sel.anchor = selection.cursor
            sel.cursor = song.totalMeasures - 1
            return sel
        } else {
            return .none
        }
    }

    private func startPlayback() {
        guard let song = song else { return }
        playbackState.mode = .playing

        let effectiveSel = effectivePlaybackSelection()
        audioEngine.startPlayback(
            song: song,
            tempo: playbackState.tempo,
            partMode: playbackState.partMode,
            currentPartName: playbackState.effectivePartName,
            audioSource: playbackState.audioSource,
            recordedAudioURLs: appState.recordedAudioURLs,
            recordingStartMeasures: appState.recordingStartMeasures,
            countInEnabled: appState.countInEnabled,
            isLooping: playbackState.isLooping,
            selection: effectiveSel
        )
    }

    private func stopPlayback() {
        audioEngine.stopPlayback()
        playbackState.mode = .stopped
        playbackMeasure = -1
        playbackBeatFraction = 0.0
    }

    private func startRecording() {
        guard let song = song,
              let partName = playbackState.effectivePartName else { return }

        playbackState.mode = .recording

        let effectiveSel = effectivePlaybackSelection()
        audioEngine.startRecording(
            partName: partName,
            song: song,
            tempo: playbackState.tempo,
            partMode: .all,
            audioSource: playbackState.audioSource,
            recordedAudioURLs: appState.recordedAudioURLs,
            recordingStartMeasures: appState.recordingStartMeasures,
            countInEnabled: appState.countInEnabled,
            monitorRecordingPart: appState.monitorRecordingPart,
            metronomeDuringRecording: appState.metronomeDuringRecording,
            isLooping: playbackState.isLooping,
            selection: effectiveSel
        )
    }

    // MARK: - File operations

    private func saveBundleAndShare() {
        if let url = appState.saveBundle() {
            shareURL = url
            showingShareSheet = true
        }
    }

    private func exportFinalMix() {
        isExporting = true
        appState.exportFinalMix { url in
            isExporting = false
            if let url = url {
                shareURL = url
                showingShareSheet = true
            }
        }
    }
}

// MARK: - Document Picker Type

enum DocumentPickerType: Identifiable {
    case song
    case bundle

    var id: String {
        switch self {
        case .song: return "song"
        case .bundle: return "bundle"
        }
    }
}

// MARK: - Document Picker (UIDocumentPickerViewController wrapper)

struct DocumentPicker_iOS: UIViewControllerRepresentable {
    let type: DocumentPickerType
    let onPick: (URL) -> Void

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

    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        let contentTypes: [UTType]
        switch type {
        case .song:
            contentTypes = [.plainText]
        case .bundle:
            // iOS doesn't let you select folders, so we let the user pick song.txt inside the bundle
            contentTypes = [.plainText]
        }

        let picker = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes)
        picker.delegate = context.coordinator
        picker.allowsMultipleSelection = false
        return picker
    }

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

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

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

        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            if let url = urls.first {
                onPick(url)
            }
        }
    }
}

// MARK: - Share Sheet (UIActivityViewController wrapper)

struct ShareSheet_iOS: UIViewControllerRepresentable {
    let activityItems: [Any]

    func makeUIViewController(context: Context) -> UIActivityViewController {
        return UIActivityViewController(
            activityItems: activityItems,
            applicationActivities: nil
        )
    }

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