import SwiftUI

/// Full-screen Now Playing view with large artwork, waveform, transport controls, and quick-add.
struct NowPlayingView: View {
    @Environment(PlayerViewModel.self) private var playerVM
    @Environment(PlaylistViewModel.self) private var playlistVM
    @EnvironmentObject private var theme: AppTheme
    @Environment(\.modelContext) private var modelContext
    @Environment(\.dismiss) private var dismiss

    @State private var isDragging = false
    @State private var dragProgress: Double = 0

    // Lyrics state
    @State private var showLyrics = false
    @State private var lyrics: [LyricsParser.LyricLine] = []
    @State private var lyricsState: LyricsState = .idle
    @State private var isSynced = false
    @State private var lastLoadedTrackID: UUID?
    @State private var showAsPlainText = false

    enum LyricsState {
        case idle
        case loading
        case loaded
        case notFound
        case error(String)
        case instrumental
    }

    var body: some View {
        NavigationStack {
            ZStack {
                theme.background.ignoresSafeArea()

                VStack(spacing: 0) {
                    if showLyrics {
                        // Lyrics mode: scrollable lyrics panel
                        lyricsPanel
                            .transition(.opacity)
                    } else {
                        // Normal mode: artwork
                        artworkSection
                            .padding(.top, 20)

                        Spacer(minLength: 16)
                    }

                    // Track info
                    trackInfoSection
                        .padding(.horizontal, 24)

                    Spacer(minLength: showLyrics ? 8 : 16)

                    // Waveform (hide in lyrics mode)
                    if !showLyrics && playerVM.showingWaveform && !playerVM.waveformSamples.isEmpty {
                        WaveformView()
                            .frame(height: 60)
                            .padding(.horizontal, 24)
                    }

                    // Seekbar + time
                    seekbarSection
                        .padding(.horizontal, 24)
                        .padding(.top, 12)

                    // Transport controls
                    transportSection
                        .padding(.top, 16)

                    // Extra controls
                    extraControlsSection
                        .padding(.top, 8)
                        .padding(.bottom, 20)
                }
            }
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button {
                        dismiss()
                    } label: {
                        Image(systemName: "chevron.down")
                            .font(.title3)
                            .foregroundStyle(theme.secondaryText)
                    }
                    .accessibilityIdentifier("nowPlayingDismiss")
                }

                ToolbarItem(placement: .topBarTrailing) {
                    HStack(spacing: 12) {
                        // Queue button
                        Button {
                            playerVM.showQueue = true
                        } label: {
                            Image(systemName: "list.bullet")
                                .foregroundStyle(theme.secondaryText)
                        }
                        .accessibilityIdentifier("queueButton")

                        // Lyrics toggle button
                        Button {
                            withAnimation(.easeInOut(duration: 0.3)) {
                                showLyrics.toggle()
                            }
                            if showLyrics {
                                if case .idle = lyricsState {
                                    loadLyrics()
                                }
                            }
                        } label: {
                            Image(systemName: showLyrics ? "text.quote.fill" : "text.quote")
                                .foregroundStyle(showLyrics ? theme.accent : theme.secondaryText)
                        }
                        .accessibilityIdentifier("lyricsButton")

                        Menu {
                            if let track = playerVM.currentTrack {
                                Button {
                                    _ = playlistVM.quickAddToTarget(track: track, context: modelContext)
                                } label: {
                                    Label("Add to Target Playlist", systemImage: "star.fill")
                                }

                                Button {
                                    playlistVM.addCuePoint(
                                        to: track,
                                        at: playerVM.currentTime,
                                        name: "Marker at \(playerVM.currentTimeFormatted)",
                                        context: modelContext
                                    )
                                    playlistVM.showStatus("Cue point added")
                                } label: {
                                    Label("Add Cue Point Here", systemImage: "bookmark.fill")
                                }
                            }
                        } label: {
                            Image(systemName: "ellipsis.circle")
                                .foregroundStyle(theme.secondaryText)
                        }
                    }
                }
            }
            .toolbarBackground(theme.background, for: .navigationBar)
            .onChange(of: playerVM.currentTrack?.id) { _, newID in
                if newID != lastLoadedTrackID {
                    loadLyrics()
                }
            }

        }
    }

    // MARK: - Artwork

    private var artworkSection: some View {
        Group {
            if let track = playerVM.currentTrack {
                LargeArtwork(track: track)
                    .frame(width: 280, height: 280)
                    .shadow(radius: 20)
                    .overlay(alignment: .bottomTrailing) {
                        if track.isCloud {
                            Image(systemName: "cloud.fill")
                                .font(.caption)
                                .foregroundStyle(.white)
                                .padding(4)
                                .background(theme.accent.opacity(0.8))
                                .clipShape(Circle())
                                .offset(x: -8, y: -8)
                        }
                    }
            } else if playerVM.isCloudPlayback {
                RoundedRectangle(cornerRadius: 16)
                    .fill(theme.cardBackground)
                    .frame(width: 280, height: 280)
                    .overlay {
                        VStack(spacing: 8) {
                            Image(systemName: "cloud.fill")
                                .font(.system(size: 60))
                                .foregroundStyle(theme.accent)
                            if playerVM.isBuffering {
                                ProgressView()
                            }
                        }
                    }
            } else {
                RoundedRectangle(cornerRadius: 16)
                    .fill(theme.cardBackground)
                    .frame(width: 280, height: 280)
                    .overlay {
                        Image(systemName: "music.note")
                            .font(.system(size: 60))
                            .foregroundStyle(theme.tertiaryText)
                    }
            }
        }
    }

    // MARK: - Track Info

    private var trackInfoSection: some View {
        VStack(spacing: 4) {
            Text(playerVM.currentTrack?.title ?? playerVM.currentCloudTrack?.title ?? "Not Playing")
                .font(.title2.bold())
                .foregroundStyle(theme.primaryText)
                .lineLimit(1)
                .accessibilityIdentifier("nowPlayingTitle")

            Text(playerVM.currentTrack?.artist ?? playerVM.currentCloudTrack?.artist ?? "")
                .font(.body)
                .foregroundStyle(theme.secondaryText)
                .lineLimit(1)
                .accessibilityIdentifier("nowPlayingArtist")

            HStack(spacing: 12) {
                if let bpm = playerVM.currentTrack?.bpm {
                    Label("\(String(format: "%.0f", bpm)) BPM", systemImage: "metronome")
                        .font(.caption)
                        .foregroundStyle(theme.tertiaryText)
                }
                if let key = playerVM.currentTrack?.musicalKey {
                    Label(key, systemImage: "music.quarternote.3")
                        .font(.caption)
                        .foregroundStyle(theme.tertiaryText)
                }
                if let format = playerVM.currentTrack?.fileFormat {
                    Text(format)
                        .font(.caption.weight(.medium))
                        .foregroundStyle(theme.tertiaryText)
                        .padding(.horizontal, 5)
                        .padding(.vertical, 1)
                        .background(theme.tertiaryText.opacity(0.15))
                        .clipShape(RoundedRectangle(cornerRadius: 3))
                }
            }
        }
    }

    // MARK: - Seekbar

    private var seekbarSection: some View {
        VStack(spacing: 4) {
            GeometryReader { geo in
                ZStack(alignment: .leading) {
                    Capsule()
                        .fill(theme.seekbarBackground)
                    Capsule()
                        .fill(theme.seekbarForeground)
                        .frame(width: max(0, (isDragging ? dragProgress : playerVM.progress) * geo.size.width))
                }
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .onChanged { value in
                            isDragging = true
                            dragProgress = max(0, min(1, value.location.x / geo.size.width))
                        }
                        .onEnded { value in
                            let prog = max(0, min(1, value.location.x / geo.size.width))
                            playerVM.seekToProgress(prog)
                            isDragging = false
                        }
                )
            }
            .frame(height: 6)

            HStack {
                Text(playerVM.currentTimeFormatted)
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(theme.secondaryText)
                Spacer()
                Text(playerVM.remainingTimeFormatted)
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(theme.secondaryText)
            }
        }
    }

    // MARK: - Transport

    private var transportSection: some View {
        HStack(spacing: 36) {
            Button { playerVM.shuffleEnabled.toggle() } label: {
                Image(systemName: "shuffle")
                    .font(.system(size: 18))
                    .foregroundStyle(playerVM.shuffleEnabled ? theme.accent : theme.tertiaryText)
                    .frame(width: 44, height: 44)
            }
            .buttonStyle(.plain)
            .accessibilityIdentifier("shuffleButton")

            Button { playerVM.playPrevious() } label: {
                Image(systemName: "backward.fill")
                    .font(.system(size: 28))
                    .foregroundStyle(theme.primaryText)
                    .frame(width: 44, height: 44)
            }
            .buttonStyle(.plain)
            .accessibilityIdentifier("previousButton")

            Button { playerVM.togglePlayPause() } label: {
                Image(systemName: playerVM.isPlaying ? "pause.circle.fill" : "play.circle.fill")
                    .font(.system(size: 64))
                    .foregroundStyle(theme.accent)
            }
            .buttonStyle(.plain)
            .accessibilityIdentifier("playPauseButton")

            Button { playerVM.playNext() } label: {
                Image(systemName: "forward.fill")
                    .font(.system(size: 28))
                    .foregroundStyle(theme.primaryText)
                    .frame(width: 44, height: 44)
            }
            .buttonStyle(.plain)
            .accessibilityIdentifier("nextButton")

            Button {
                switch playerVM.repeatMode {
                case .off: playerVM.repeatMode = .all
                case .all: playerVM.repeatMode = .one
                case .one: playerVM.repeatMode = .off
                }
            } label: {
                Image(systemName: playerVM.repeatMode.icon)
                    .font(.system(size: 18))
                    .foregroundStyle(playerVM.repeatMode != .off ? theme.accent : theme.tertiaryText)
                    .frame(width: 44, height: 44)
            }
            .buttonStyle(.plain)
        }
    }

    // MARK: - Extra Controls

    private static let mixColors: [Color] = [
        Color(red: 0.95, green: 0.3, blue: 0.3),
        Color(red: 0.3, green: 0.75, blue: 0.95),
        Color(red: 0.95, green: 0.75, blue: 0.2),
    ]

    private var extraControlsSection: some View {
        HStack(spacing: 20) {
            // 3 Mix buttons
            ForEach(0..<3, id: \.self) { slot in
                Button {
                    guard let track = playerVM.currentTrack else { return }
                    _ = playlistVM.quickAddToMix(slot: slot, track: track, context: modelContext)
                } label: {
                    VStack(spacing: 4) {
                        Text("\(slot + 1)")
                            .font(.system(size: 16, weight: .bold, design: .rounded))
                            .frame(width: 36, height: 36)
                            .foregroundStyle(
                                playlistVM.mixTargets[slot] != nil
                                    ? Self.mixColors[slot]
                                    : theme.tertiaryText
                            )
                            .background(
                                playlistVM.mixTargets[slot] != nil
                                    ? Self.mixColors[slot].opacity(0.15)
                                    : theme.tertiaryText.opacity(0.08)
                            )
                            .clipShape(RoundedRectangle(cornerRadius: 8))
                        Text(playlistVM.mixTargetName(slot))
                            .font(.system(size: 9))
                            .foregroundStyle(theme.tertiaryText)
                            .lineLimit(1)
                    }
                    .frame(minWidth: 50, minHeight: 44)
                }
                .buttonStyle(.plain)
            }

            Spacer()

            // Skip backward
            Button { playerVM.skipBackward() } label: {
                VStack(spacing: 4) {
                    Image(systemName: "gobackward.10")
                        .font(.system(size: 20))
                    Text("-10s")
                        .font(.caption2)
                }
                .foregroundStyle(theme.secondaryText)
                .frame(minWidth: 44, minHeight: 44)
            }
            .buttonStyle(.plain)

            // Skip forward
            Button { playerVM.skipForward() } label: {
                VStack(spacing: 4) {
                    Image(systemName: "goforward.10")
                        .font(.system(size: 20))
                    Text("+10s")
                        .font(.caption2)
                }
                .foregroundStyle(theme.secondaryText)
                .frame(minWidth: 44, minHeight: 44)
            }
            .buttonStyle(.plain)
        }
        .padding(.horizontal, 24)
    }

    // MARK: - Lyrics Panel

    private var lyricsPanel: some View {
        VStack(spacing: 0) {
            // Lyrics header with synced/plain toggle
            HStack {
                Text("Lyrics")
                    .font(.headline)
                    .foregroundStyle(theme.secondaryText)
                Spacer()
                if case .loaded = lyricsState, isSynced {
                    Button {
                        showAsPlainText.toggle()
                    } label: {
                        HStack(spacing: 4) {
                            Image(systemName: showAsPlainText ? "text.alignleft" : "waveform")
                                .font(.system(size: 10))
                            Text(showAsPlainText ? "Plain" : "Synced")
                                .font(.caption)
                        }
                        .padding(.horizontal, 8)
                        .padding(.vertical, 3)
                        .background(showAsPlainText ? theme.tertiaryText.opacity(0.15) : theme.accent.opacity(0.2))
                        .foregroundStyle(showAsPlainText ? theme.secondaryText : theme.accent)
                        .clipShape(Capsule())
                    }
                    .buttonStyle(.plain)
                }
            }
            .padding(.horizontal, 24)
            .padding(.top, 12)
            .padding(.bottom, 4)

            // Lyrics content
            switch lyricsState {
            case .idle, .loading:
                Spacer()
                ProgressView()
                    .scaleEffect(0.8)
                Text("Searching for lyrics…")
                    .font(.callout)
                    .foregroundStyle(theme.tertiaryText)
                    .padding(.top, 8)
                Spacer()

            case .notFound:
                Spacer()
                VStack(spacing: 12) {
                    Image(systemName: "text.page.slash")
                        .font(.system(size: 36))
                        .foregroundStyle(theme.tertiaryText)
                    Text("No lyrics found")
                        .font(.title3)
                        .foregroundStyle(theme.secondaryText)
                    if let track = playerVM.currentTrack {
                        Text("\(track.artist) — \(track.title)")
                            .font(.caption)
                            .foregroundStyle(theme.tertiaryText)
                    }
                }
                Spacer()

            case .instrumental:
                Spacer()
                VStack(spacing: 12) {
                    Image(systemName: "pianokeys")
                        .font(.system(size: 36))
                        .foregroundStyle(theme.tertiaryText)
                    Text("Instrumental")
                        .font(.title3)
                        .foregroundStyle(theme.secondaryText)
                }
                Spacer()

            case .error(let message):
                Spacer()
                VStack(spacing: 12) {
                    Image(systemName: "exclamationmark.triangle")
                        .font(.system(size: 36))
                        .foregroundStyle(theme.tertiaryText)
                    Text(message)
                        .font(.callout)
                        .foregroundStyle(theme.secondaryText)
                }
                Spacer()

            case .loaded:
                if isSynced && !showAsPlainText {
                    SyncedLyricsView(
                        lines: lyrics,
                        currentTime: playerVM.currentTime,
                        accent: theme.accent,
                        secondaryText: theme.secondaryText,
                        primaryText: theme.primaryText,
                        onSeek: { time in playerVM.seek(to: time) }
                    )
                } else {
                    PlainLyricsView(lines: lyrics, primaryText: theme.primaryText)
                }
            }
        }
        .accessibilityIdentifier("lyricsPanel")
    }

    // MARK: - Lyrics Loading

    private func loadLyrics() {
        guard let track = playerVM.currentTrack else {
            lyricsState = .idle
            lyrics = []
            return
        }

        lastLoadedTrackID = track.id
        lyricsState = .loading
        lyrics = []

        Task {
            do {
                let result = try await LRCLIBService.shared.fetchLyrics(
                    artist: track.artist,
                    title: track.title,
                    album: track.album.isEmpty ? nil : track.album,
                    duration: track.duration
                )

                if result.isInstrumental {
                    lyricsState = .instrumental
                    return
                }

                if let synced = result.syncedLyrics, !synced.isEmpty {
                    lyrics = LyricsParser.parseSynced(synced)
                    isSynced = true
                    lyricsState = .loaded
                } else if let plain = result.plainLyrics, !plain.isEmpty {
                    lyrics = LyricsParser.parsePlain(plain)
                    isSynced = false
                    lyricsState = .loaded
                } else {
                    lyricsState = .notFound
                }
            } catch is LyricsError {
                lyricsState = .notFound
            } catch {
                lyricsState = .error(error.localizedDescription)
            }
        }
    }
}

// MARK: - Large Artwork

struct LargeArtwork: View {
    let track: Track
    @EnvironmentObject private var theme: AppTheme
    @State private var artwork: UIImage?

    var body: some View {
        Group {
            if let image = artwork {
                Image(uiImage: image)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
            } else {
                ZStack {
                    RoundedRectangle(cornerRadius: 16)
                        .fill(theme.cardBackground)
                    Image(systemName: "music.note")
                        .font(.system(size: 60))
                        .foregroundStyle(theme.tertiaryText)
                }
            }
        }
        .clipShape(RoundedRectangle(cornerRadius: 16))
        .task {
            let url = track.fileURL
            artwork = await ArtworkService.shared.artwork(for: url)
        }
    }
}

// MARK: - Volume Slider

struct VolumeSlider: View {
    @Environment(PlayerViewModel.self) private var playerVM
    @EnvironmentObject private var theme: AppTheme

    var body: some View {
        VStack(spacing: 4) {
            Image(systemName: volumeIcon)
                .font(.system(size: 20))
                .foregroundStyle(theme.secondaryText)
            Text("\(Int(playerVM.volume * 100))%")
                .font(.caption2)
                .foregroundStyle(theme.tertiaryText)
        }
        .onTapGesture {
            // Toggle between mute and previous volume
            if playerVM.volume > 0 {
                playerVM.volume = 0
            } else {
                playerVM.volume = 0.8
            }
        }
    }

    private var volumeIcon: String {
        if playerVM.volume == 0 { return "speaker.slash" }
        if playerVM.volume < 0.3 { return "speaker.wave.1" }
        if playerVM.volume < 0.7 { return "speaker.wave.2" }
        return "speaker.wave.3"
    }
}

// MARK: - Synced Lyrics View (auto-scrolling, highlighted)

struct SyncedLyricsView: View {
    let lines: [LyricsParser.LyricLine]
    let currentTime: TimeInterval
    let accent: Color
    let secondaryText: Color
    let primaryText: Color
    let onSeek: (TimeInterval) -> Void

    @State private var currentIndex: Int?

    var body: some View {
        ScrollViewReader { proxy in
            ScrollView {
                LazyVStack(alignment: .leading, spacing: 8) {
                    Spacer()
                        .frame(height: 20)

                    ForEach(Array(lines.enumerated()), id: \.element.id) { index, line in
                        let isCurrent = index == currentIndex

                        Text(line.text.isEmpty ? "♪" : line.text)
                            .font(.system(size: isCurrent ? 20 : 17, weight: isCurrent ? .semibold : .regular))
                            .foregroundStyle(isCurrent ? accent : (index < (currentIndex ?? 0) ? secondaryText : primaryText))
                            .opacity(isCurrent ? 1.0 : (index < (currentIndex ?? 0) ? 0.5 : 0.7))
                            .padding(.horizontal, 24)
                            .padding(.vertical, 2)
                            .id(line.id)
                            .onTapGesture {
                                onSeek(line.timestamp)
                            }
                            .animation(.easeInOut(duration: 0.3), value: isCurrent)
                    }

                    Spacer()
                        .frame(height: 60)
                }
            }
            .onChange(of: currentTime) { _, time in
                let newIndex = LyricsParser.currentLineIndex(in: lines, at: time)
                if newIndex != currentIndex {
                    currentIndex = newIndex
                    if let idx = newIndex, idx < lines.count {
                        withAnimation(.easeInOut(duration: 0.4)) {
                            proxy.scrollTo(lines[idx].id, anchor: .center)
                        }
                    }
                }
            }
            .onAppear {
                currentIndex = LyricsParser.currentLineIndex(in: lines, at: currentTime)
                if let idx = currentIndex, idx < lines.count {
                    proxy.scrollTo(lines[idx].id, anchor: .center)
                }
            }
        }
    }
}

// MARK: - Plain Lyrics View (no timestamps)

struct PlainLyricsView: View {
    let lines: [LyricsParser.LyricLine]
    let primaryText: Color

    var body: some View {
        ScrollView {
            LazyVStack(alignment: .leading, spacing: 6) {
                Spacer()
                    .frame(height: 16)

                ForEach(lines) { line in
                    Text(line.text.isEmpty ? " " : line.text)
                        .font(.system(size: 16))
                        .foregroundStyle(line.text.isEmpty ? .clear : primaryText.opacity(0.8))
                        .padding(.horizontal, 24)
                }

                Spacer()
                    .frame(height: 40)
            }
        }
    }
}
