import SwiftData
import SwiftUI
import UniformTypeIdentifiers

/// Library tab — browse and manage imported audio files.
/// Five browse modes: Songs (flat), Artists, Albums, Genres, Folders.
struct LibraryView: View {
    @Environment(PlayerViewModel.self) private var playerVM
    @Environment(PlaylistViewModel.self) private var playlistVM
    @EnvironmentObject private var libraryManager: LibraryManager
    @EnvironmentObject private var theme: AppTheme
    @Environment(\.modelContext) private var modelContext

    @Query(sort: \Track.dateAdded, order: .reverse) private var tracks: [Track]

    @State private var showImporter = false
    @State private var showFolderImporter = false
    @State private var searchText = ""
    @State private var showAddToPlaylist: Track?
    @State private var browseMode: BrowseMode = .folders
    @State private var sortOrder: SortOrder = .dateAdded
    @State private var hasScanned = false

    enum BrowseMode: String, CaseIterable {
        case folders = "Folders"
        case songs = "Songs"
        case artists = "Artists"
        case albums = "Albums"
        case genres = "Genres"
    }

    enum SortOrder: String, CaseIterable {
        case dateAdded = "Date Added"
        case title = "Title"
        case artist = "Artist"
        case bpm = "BPM"
        case duration = "Duration"
    }

    // MARK: - Filtered & Sorted Tracks

    private var filteredTracks: [Track] {
        let base: [Track]
        switch sortOrder {
        case .dateAdded: base = tracks
        case .title: base = tracks.sorted { $0.title.localizedCaseInsensitiveCompare($1.title) == .orderedAscending }
        case .artist: base = tracks.sorted { $0.artist.localizedCaseInsensitiveCompare($1.artist) == .orderedAscending }
        case .bpm: base = tracks.sorted { ($0.bpm ?? 0) < ($1.bpm ?? 0) }
        case .duration: base = tracks.sorted { $0.duration < $1.duration }
        }

        if searchText.isEmpty { return base }
        let query = searchText.lowercased()
        return base.filter {
            $0.title.lowercased().contains(query) ||
            $0.artist.lowercased().contains(query) ||
            $0.album.lowercased().contains(query)
        }
    }

    // MARK: - Grouped Data

    private var artistGroups: [(String, [Track])] {
        let grouped = Dictionary(grouping: filteredTracks) { $0.artist.isEmpty ? "Unknown Artist" : $0.artist }
        return grouped.sorted { $0.key.localizedCaseInsensitiveCompare($1.key) == .orderedAscending }
    }

    private var albumGroups: [(String, [Track])] {
        let grouped = Dictionary(grouping: filteredTracks) {
            let artist = $0.artist.isEmpty ? "Unknown" : $0.artist
            let album = $0.album.isEmpty ? "Unknown Album" : $0.album
            return "\(artist) — \(album)"
        }
        return grouped.sorted { $0.key.localizedCaseInsensitiveCompare($1.key) == .orderedAscending }
    }

    private var genreGroups: [(String, [Track])] {
        let grouped = Dictionary(grouping: filteredTracks) { $0.genre.isEmpty ? "Unknown Genre" : $0.genre }
        return grouped.sorted { $0.key.localizedCaseInsensitiveCompare($1.key) == .orderedAscending }
    }

    private var folderGroups: [(String, [Track])] {
        let grouped = Dictionary(grouping: filteredTracks) { track -> String in
            let components = track.filePath.split(separator: "/").dropLast()
            return components.isEmpty ? "/" : components.joined(separator: "/")
        }
        return grouped.sorted { $0.key.localizedCaseInsensitiveCompare($1.key) == .orderedAscending }
    }

    // MARK: - Body

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                if !tracks.isEmpty {
                    // Browse mode picker
                    ScrollView(.horizontal, showsIndicators: false) {
                        HStack(spacing: 8) {
                            ForEach(BrowseMode.allCases, id: \.self) { mode in
                                Button {
                                    withAnimation(.easeInOut(duration: 0.2)) {
                                        browseMode = mode
                                    }
                                } label: {
                                    Text(mode.rawValue)
                                        .font(.subheadline.weight(browseMode == mode ? .semibold : .regular))
                                        .padding(.horizontal, 14)
                                        .padding(.vertical, 6)
                                        .background(browseMode == mode ? theme.accent.opacity(0.2) : Color.clear)
                                        .foregroundStyle(browseMode == mode ? theme.accent : theme.secondaryText)
                                        .clipShape(Capsule())
                                        .overlay(
                                            Capsule()
                                                .stroke(browseMode == mode ? theme.accent.opacity(0.5) : theme.separatorColor, lineWidth: 1)
                                        )
                                }
                                .buttonStyle(.plain)
                            }
                        }
                        .padding(.horizontal, 16)
                        .padding(.vertical, 8)
                    }

                    Divider()
                }

                Group {
                    if tracks.isEmpty {
                        emptyState
                    } else {
                        mainList
                    }
                }
            }
            .navigationTitle("Library")
            .accessibilityIdentifier("libraryView")
            .searchable(text: $searchText, prompt: "Search tracks")
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Menu {
                        ForEach(SortOrder.allCases, id: \.self) { order in
                            Button {
                                sortOrder = order
                            } label: {
                                HStack {
                                    Text(order.rawValue)
                                    if sortOrder == order {
                                        Image(systemName: "checkmark")
                                    }
                                }
                            }
                        }
                    } label: {
                        Image(systemName: "arrow.up.arrow.down")
                    }
                }

                ToolbarItem(placement: .topBarTrailing) {
                    Menu {
                        Button {
                            showImporter = true
                        } label: {
                            Label("Import Files", systemImage: "doc.badge.plus")
                        }

                        Button {
                            showFolderImporter = true
                        } label: {
                            Label("Import Folder", systemImage: "folder.badge.plus")
                        }

                        Button {
                            Task { await libraryManager.scanMusicDirectory() }
                        } label: {
                            Label("Scan Music Folder", systemImage: "arrow.clockwise")
                        }
                    } label: {
                        Image(systemName: "plus")
                    }
                }

                if !tracks.filter({ !$0.isAnalyzed }).isEmpty {
                    ToolbarItem(placement: .topBarTrailing) {
                        Button {
                            Task { await libraryManager.analyzeAllTracks(tracks: tracks) }
                        } label: {
                            Image(systemName: "waveform.badge.magnifyingglass")
                        }
                    }
                }
            }
            .fileImporter(
                isPresented: $showImporter,
                allowedContentTypes: [
                    .mp3, .wav, .aiff,
                    UTType(filenameExtension: "flac") ?? .audio,
                    UTType(filenameExtension: "m4a") ?? .audio,
                    UTType(filenameExtension: "ogg") ?? .audio,
                    .audio
                ],
                allowsMultipleSelection: true
            ) { result in
                if case .success(let urls) = result {
                    Task { await libraryManager.importFiles(urls) }
                }
            }
            .fileImporter(
                isPresented: $showFolderImporter,
                allowedContentTypes: [.folder],
                allowsMultipleSelection: true
            ) { result in
                if case .success(let urls) = result {
                    Task { await libraryManager.importFiles(urls) }
                }
            }
            .sheet(item: $showAddToPlaylist) { track in
                AddToPlaylistSheet(track: track)
                    .environmentObject(theme)
            }
            .sheet(isPresented: Binding(
                get: { showAddGroupToPlaylist != nil },
                set: { if !$0 { showAddGroupToPlaylist = nil } }
            )) {
                if let tracks = showAddGroupToPlaylist {
                    AddGroupToPlaylistSheet(tracks: tracks)
                        .environmentObject(theme)
                }
            }
            .task(id: "initialScan") {
                // Only scan once when the view first appears, not on every tab switch
                guard !hasScanned else { return }
                hasScanned = true
                await libraryManager.scanMusicDirectory()
            }
        }
    }

    // MARK: - Main List

    @ViewBuilder
    private var mainList: some View {
        if browseMode == .folders {
            // Folders mode: show drill-down browser directly
            FolderBrowserView(
                folderURL: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!,
                title: "Music"
            )
        } else {
            List {
                if libraryManager.isScanning {
                    scanningRow
                }

                switch browseMode {
                case .songs:
                    songsList
                case .artists:
                    groupedList(groups: artistGroups, icon: "person.fill")
                case .albums:
                    groupedList(groups: albumGroups, icon: "square.stack.fill")
                case .genres:
                    groupedList(groups: genreGroups, icon: "guitars.fill")
                case .folders:
                    EmptyView() // handled above
                }

                footer
            }
            .listStyle(.plain)
        }
    }

    // MARK: - Songs (flat list)

    private var songsList: some View {
        ForEach(filteredTracks) { track in
            trackRow(track)
        }
    }

    // MARK: - Grouped list

    @State private var showAddGroupToPlaylist: [Track]?

    private func groupedList(groups: [(String, [Track])], icon: String) -> some View {
        ForEach(groups, id: \.0) { groupName, groupTracks in
            Section {
                // Action row for the whole group
                groupActionRow(groupTracks)

                ForEach(groupTracks) { track in
                    trackRow(track)
                }
            } header: {
                HStack(spacing: 8) {
                    Image(systemName: icon)
                        .font(.caption)
                        .foregroundStyle(theme.accent)
                    Text(groupName)
                        .font(.subheadline.weight(.semibold))
                        .foregroundStyle(theme.groupHeaderText)

                    Spacer()

                    Text("\(groupTracks.count)")
                        .font(.caption)
                        .foregroundStyle(theme.tertiaryText)

                    let totalDuration = groupTracks.reduce(0) { $0 + $1.duration }
                    Text(formatDuration(totalDuration))
                        .font(.caption.monospacedDigit())
                        .foregroundStyle(theme.tertiaryText)
                }
            }
        }
    }

    // MARK: - Group Action Row (play all, add all to mix/playlist)

    private func groupActionRow(_ tracks: [Track]) -> some View {
        HStack(spacing: 12) {
            // Play all
            Button {
                if let first = tracks.first {
                    playerVM.loadAndPlay(first)
                }
            } label: {
                Label("Play", systemImage: "play.fill")
                    .font(.caption)
                    .foregroundStyle(theme.accent)
            }
            .buttonStyle(.plain)

            Divider().frame(height: 16)

            // Mix buttons
            ForEach(0..<3, id: \.self) { slot in
                if playlistVM.mixTargets[slot] != nil {
                    Button {
                        for track in tracks {
                            _ = playlistVM.quickAddToMix(slot: slot, track: track, context: modelContext)
                        }
                        playlistVM.showStatus("Added \(tracks.count) to \(playlistVM.mixTargetName(slot))")
                    } label: {
                        Text("\(slot + 1)")
                            .font(.system(size: 11, weight: .bold, design: .rounded))
                            .frame(width: 24, height: 24)
                            .foregroundStyle(Self.mixColors[slot])
                            .background(Self.mixColors[slot].opacity(0.15))
                            .clipShape(RoundedRectangle(cornerRadius: 5))
                    }
                    .buttonStyle(.plain)
                }
            }

            Divider().frame(height: 16)

            // Add to playlist
            Button {
                showAddGroupToPlaylist = tracks
            } label: {
                Image(systemName: "plus.circle")
                    .font(.system(size: 16))
                    .foregroundStyle(theme.secondaryText)
            }
            .buttonStyle(.plain)

            Spacer()
        }
        .padding(.vertical, 4)
        .listRowBackground(theme.cardBackground.opacity(0.3))
    }

    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),
    ]

    // MARK: - Track Row with actions

    private func trackRow(_ track: Track) -> some View {
        Button {
            playerVM.loadAndPlay(track)
            playerVM.showNowPlaying = true
        } label: {
            TrackRow(track: track)
                .contentShape(Rectangle())
        }
        .buttonStyle(.plain)
            .swipeActions(edge: .trailing) {
                Button(role: .destructive) {
                    libraryManager.removeTrack(track)
                    try? modelContext.save()
                } label: {
                    Label("Delete", systemImage: "trash")
                }

                Button {
                    showAddToPlaylist = track
                } label: {
                    Label("Add to...", systemImage: "plus.circle")
                }
                .tint(theme.accent)
            }
            .swipeActions(edge: .leading) {
                Button {
                    _ = playlistVM.quickAddToTarget(track: track, context: modelContext)
                } label: {
                    Label("Quick Add", systemImage: "star.fill")
                }
                .tint(.orange)
            }
            .contextMenu {
                Button {
                    _ = playlistVM.quickAddToTarget(track: track, context: modelContext)
                } label: {
                    Label("Add to Target Playlist", systemImage: "star.fill")
                }

                Button {
                    showAddToPlaylist = track
                } label: {
                    Label("Add to Playlist...", systemImage: "plus.circle")
                }

                if !track.isAnalyzed {
                    Button {
                        Task { await libraryManager.analyzeTrack(track) }
                    } label: {
                        Label("Analyze BPM & Key", systemImage: "waveform.badge.magnifyingglass")
                    }
                }

                Divider()

                Button(role: .destructive) {
                    libraryManager.removeTrack(track)
                    try? modelContext.save()
                } label: {
                    Label("Delete", systemImage: "trash")
                }
            }
    }

    // MARK: - Scanning Row

    private var scanningRow: some View {
        HStack(spacing: 12) {
            ProgressView()
            VStack(alignment: .leading, spacing: 2) {
                Text("Importing...")
                    .foregroundStyle(theme.secondaryText)
                if !libraryManager.scanStatus.isEmpty {
                    Text(libraryManager.scanStatus)
                        .font(.caption)
                        .foregroundStyle(theme.tertiaryText)
                        .lineLimit(1)
                }
            }
        }
    }

    // MARK: - Footer

    @ViewBuilder
    private var footer: some View {
        if !filteredTracks.isEmpty {
            VStack(spacing: 2) {
                Text("\(filteredTracks.count) tracks")
                    .font(.caption)
                    .foregroundStyle(theme.tertiaryText)

                let totalDuration = filteredTracks.reduce(0) { $0 + $1.duration }
                Text(formatDuration(totalDuration))
                    .font(.caption.monospacedDigit())
                    .foregroundStyle(theme.tertiaryText)
            }
            .frame(maxWidth: .infinity, alignment: .center)
            .listRowBackground(Color.clear)
        }
    }

    // MARK: - Empty State

    private var emptyState: some View {
        VStack(spacing: 20) {
            Spacer()
            Image(systemName: "music.note.house")
                .font(.system(size: 60))
                .foregroundStyle(theme.tertiaryText)
            Text("No tracks yet")
                .font(.title2)
                .foregroundStyle(theme.secondaryText)
            Text("Import your MP3, FLAC, OGG, and other audio files")
                .font(.subheadline)
                .foregroundStyle(theme.tertiaryText)
                .multilineTextAlignment(.center)
            Button {
                showImporter = true
            } label: {
                Label("Import Files", systemImage: "plus.circle.fill")
                    .font(.headline)
                    .padding(.horizontal, 24)
                    .padding(.vertical, 12)
            }
            .buttonStyle(.borderedProminent)
            .tint(theme.accent)
            Spacer()
        }
        .padding()
    }

    // MARK: - Helpers

    private func formatDuration(_ total: TimeInterval) -> String {
        let t = Int(total)
        let hours = t / 3600
        let minutes = (t % 3600) / 60
        let seconds = t % 60
        if hours > 0 {
            return String(format: "%d:%02d:%02d", hours, minutes, seconds)
        }
        return String(format: "%d:%02d", minutes, seconds)
    }
}
