import SwiftUI
import UniformTypeIdentifiers

// MARK: - Main Window

/// The main content view of the app, assembling the toolbar, legend, and sheet music.
struct MainWindow: View {
    @EnvironmentObject var appState: AppState
    @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
    @State private var showingParseError = false
    @State private var parseErrorMessage = ""

    private var song: Song? {
        appState.currentSong
    }

    var body: some View {
        VStack(spacing: 0) {
            if let song = song {
                // Toolbar — pass callbacks for play/stop/record
                ToolbarView(
                    playbackState: playbackState,
                    partNames: song.partNames,
                    onPlay: { startPlayback() },
                    onStop: { stopPlayback() },
                    onRecord: { startRecording() },
                    onStopRecording: { stopPlayback() }
                )

                Divider()

                // Legend bar with recording indicators
                LegendBar(
                    parts: song.parts,
                    recordedParts: playbackState.recordedParts
                )
                Divider()

                // Sheet music content area
                SheetMusicViewContainer(
                    song: song,
                    selection: $selection,
                    playbackMeasure: $playbackMeasure,
                    playbackBeatFraction: $playbackBeatFraction
                )
            } else {
                Spacer()
                VStack(spacing: 12) {
                    Image(systemName: "music.note.list")
                        .font(.system(size: 48))
                        .foregroundColor(.secondary)
                    Text("Open a song file to begin")
                        .font(.title2)
                        .foregroundColor(.secondary)
                    Text("File → Open Song... (⌘O)")
                        .font(.caption)
                        .foregroundColor(Color(nsColor: .tertiaryLabelColor))
                }
                Spacer()
            }
        }
        .frame(minWidth: 800, minHeight: 600)
        .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)
        }
        .alert("Error Opening File", isPresented: $showingParseError) {
            Button("OK") { }
        } message: {
            Text(parseErrorMessage)
        }
    }

    // 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
            appState.applyPitchCorrection(partName: partName)
        }
    }

    /// Build the effective selection for playback:
    /// - If there's a multi-measure selection range, use that
    /// - If there's just a cursor, play from cursor to end
    /// - If nothing, play from beginning
    private func effectivePlaybackSelection() -> Selection {
        if selection.hasSelection {
            // Use the selection range as-is
            return selection
        } else if selection.cursor >= 0, let song = song {
            // Cursor only — play from cursor to end of 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()
        // During recording, always play ALL parts as backing
        // (the excludePartName mechanism handles muting the recording part)
        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
        )
    }
}
