import SwiftUI
import SwiftData

struct TranscriptionHistoryView: View {
    @Environment(\.modelContext) private var modelContext
    @State private var searchText = ""
    @State private var selectedTranscription: Transcription?
    @State private var selectedTranscriptions: Set<Transcription> = []
    @State private var showDeleteConfirmation = false
    @State private var isViewCurrentlyVisible = false
    @State private var isAnalysisPanelPresented = false
    @State private var isLeftSidebarVisible = true
    @State private var isRightSidebarVisible = true
    @State private var leftSidebarWidth: CGFloat = 300
    @State private var rightSidebarWidth: CGFloat = 350
    @State private var displayedTranscriptions: [Transcription] = []
    @State private var isLoading = false
    @State private var hasMoreContent = true
    @State private var lastTimestamp: Date?

    private let exportService = VoiceInkCSVExportService()
    private let pageSize = 20
    
    @Query(Self.createLatestTranscriptionIndicatorDescriptor()) private var latestTranscriptionIndicator: [Transcription]

    private static func createLatestTranscriptionIndicatorDescriptor() -> FetchDescriptor<Transcription> {
        var descriptor = FetchDescriptor<Transcription>(
            sortBy: [SortDescriptor(\.timestamp, order: .reverse)]
        )
        descriptor.fetchLimit = 1
        return descriptor
    }

    private func cursorQueryDescriptor(after timestamp: Date? = nil) -> FetchDescriptor<Transcription> {
        var descriptor = FetchDescriptor<Transcription>(
            sortBy: [SortDescriptor(\Transcription.timestamp, order: .reverse)]
        )

        if let timestamp = timestamp {
            if !searchText.isEmpty {
                descriptor.predicate = #Predicate<Transcription> { transcription in
                    (transcription.text.localizedStandardContains(searchText) ||
                    (transcription.enhancedText?.localizedStandardContains(searchText) ?? false)) &&
                    transcription.timestamp < timestamp
                }
            } else {
                descriptor.predicate = #Predicate<Transcription> { transcription in
                    transcription.timestamp < timestamp
                }
            }
        } else if !searchText.isEmpty {
            descriptor.predicate = #Predicate<Transcription> { transcription in
                transcription.text.localizedStandardContains(searchText) ||
                (transcription.enhancedText?.localizedStandardContains(searchText) ?? false)
            }
        }
        
        descriptor.fetchLimit = pageSize
        return descriptor
    }
    
    var body: some View {
        HStack(spacing: 0) {
            if isLeftSidebarVisible {
                leftSidebarView
                    .frame(width: leftSidebarWidth)
                    .transition(.move(edge: .leading))

                Divider()
            }

            centerPaneView
                .frame(maxWidth: .infinity)

            if isRightSidebarVisible {
                Divider()

                rightSidebarView
                    .frame(width: rightSidebarWidth)
                    .transition(.move(edge: .trailing))
            }
        }
        .toolbar {
            ToolbarItemGroup(placement: .navigation) {
                Button(action: { withAnimation { isLeftSidebarVisible.toggle() } }) {
                    Label("Zijbalk tonen/verbergen", systemImage: "sidebar.left")
                }
            }

            ToolbarItemGroup(placement: .automatic) {
                Button(action: { withAnimation { isRightSidebarVisible.toggle() } }) {
                    Label("Inspector tonen/verbergen", systemImage: "sidebar.right")
                }
            }
        }
        .alert("Geselecteerde items verwijderen?", isPresented: $showDeleteConfirmation) {
            Button("Verwijderen", role: .destructive) {
                deleteSelectedTranscriptions()
            }
            Button("Annuleren", role: .cancel) {}
        } message: {
            Text("Dit kan niet ongedaan worden gemaakt. Weet je zeker dat je \(selectedTranscriptions.count) \(selectedTranscriptions.count == 1 ? "item" : "items") wilt verwijderen?")
        }
        .overlay {
            Color.black.opacity(isAnalysisPanelPresented ? 0.1 : 0)
                .ignoresSafeArea()
                .allowsHitTesting(isAnalysisPanelPresented)
                .onTapGesture {
                    withAnimation(.smooth(duration: 0.3)) {
                        isAnalysisPanelPresented = false
                    }
                }
                .animation(.smooth(duration: 0.3), value: isAnalysisPanelPresented)
        }
        .overlay(alignment: .trailing) {
            if isAnalysisPanelPresented {
                PerformanceAnalysisPanelView(
                    transcriptions: Array(selectedTranscriptions),
                    onClose: {
                        withAnimation(.smooth(duration: 0.3)) {
                            isAnalysisPanelPresented = false
                        }
                    }
                )
                .id(selectedTranscriptions.count)
                .frame(width: 400)
                .frame(maxHeight: .infinity)
                .background(Color.proatBgRaised)
                .overlay(alignment: .leading) {
                    Rectangle()
                        .fill(Color.proatBorder)
                        .frame(width: 1)
                }
                .proatShadowFloat()
                .ignoresSafeArea()
                .transition(.move(edge: .trailing))
            }
        }
        .animation(.smooth(duration: 0.3), value: isAnalysisPanelPresented)
        .onAppear {
            isViewCurrentlyVisible = true
            Task {
                await loadInitialContent()
            }
        }
        .onDisappear {
            isViewCurrentlyVisible = false
        }
        .onChange(of: searchText) { _, _ in
            Task {
                await resetPagination()
                await loadInitialContent()
            }
        }
        .onChange(of: latestTranscriptionIndicator.first?.id) { oldId, newId in
            guard isViewCurrentlyVisible else { return }
            if newId != oldId {
                Task {
                    await resetPagination()
                    await loadInitialContent()
                }
            }
        }
    }

    private var leftSidebarView: some View {
        VStack(spacing: 0) {
            HStack {
                Image(systemName: "magnifyingglass")
                    .foregroundColor(.proatText3)
                    .font(.system(size: 13))
                TextField("Transcripties zoeken", text: $searchText)
                    .textFieldStyle(PlainTextFieldStyle())
                    .font(ProatFont.body)
                    .foregroundColor(.proatText1)
            }
            .padding(ProatSpacing.xs)
            .background(
                RoundedRectangle(cornerRadius: ProatRadius.knop, style: .continuous)
                    .fill(Color.proatBgSunken)
                    .overlay(
                        RoundedRectangle(cornerRadius: ProatRadius.knop, style: .continuous)
                            .stroke(Color.proatBorder, lineWidth: 1)
                    )
            )
            .padding(ProatSpacing.s)

            Rectangle().fill(Color.proatBorder).frame(height: 1)

            ZStack(alignment: .bottom) {
                if displayedTranscriptions.isEmpty && !isLoading {
                    VStack(spacing: ProatSpacing.s) {
                        ProatBrandMark(size: 32, showCaption: false, opacity: 0.5)
                        Image(systemName: "doc.text.magnifyingglass")
                            .font(.system(size: 40))
                            .foregroundColor(.proatTeal)
                        Text("Geen transcripties")
                            .font(ProatFont.body)
                            .foregroundColor(.proatText2)
                    }
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                } else {
                    ScrollView {
                        LazyVStack(spacing: 8) {
                            ForEach(displayedTranscriptions) { transcription in
                                TranscriptionListItem(
                                    transcription: transcription,
                                    isSelected: selectedTranscription == transcription,
                                    isChecked: selectedTranscriptions.contains(transcription),
                                    onSelect: { selectedTranscription = transcription },
                                    onToggleCheck: { toggleSelection(transcription) }
                                )
                            }

                            if hasMoreContent {
                                Button(action: {
                                    Task { await loadMoreContent() }
                                }) {
                                    HStack(spacing: 8) {
                                        if isLoading {
                                            ProgressView().controlSize(.small)
                                        }
                                        Text(isLoading ? "Laden…" : "Meer laden")
                                            .font(ProatFont.klein)
                                            .fontWeight(.medium)
                                            .foregroundColor(.proatTeal)
                                    }
                                    .frame(maxWidth: .infinity)
                                    .padding(.vertical, ProatSpacing.xs)
                                }
                                .buttonStyle(.plain)
                                .disabled(isLoading)
                            }
                        }
                        .padding(8)
                        .padding(.bottom, 50)
                    }
                }

                if !displayedTranscriptions.isEmpty {
                    selectionToolbar
                        .transition(.move(edge: .bottom).combined(with: .opacity))
                }
            }
        }
        .background(Color.proatBgSunken)
    }

    private var centerPaneView: some View {
        Group {
            if let transcription = selectedTranscription {
                TranscriptionDetailView(transcription: transcription, onInfoTap: {
                    withAnimation { isRightSidebarVisible.toggle() }
                })
                    .id(transcription.id)
            } else {
                ScrollView {
                    VStack(spacing: ProatSpacing.xl) {
                        Spacer()
                            .frame(minHeight: 40)

                        VStack(spacing: ProatSpacing.s) {
                            Image(systemName: "doc.text")
                                .font(.system(size: 50))
                                .foregroundColor(.proatTeal)
                            Text("Niets geselecteerd")
                                .font(ProatFont.titel)
                                .foregroundColor(.proatText1)
                            Text("Kies een transcriptie voor details")
                                .font(ProatFont.body)
                                .foregroundColor(.proatText2)
                        }

                        HistoryShortcutTipView()
                            .padding(.horizontal, ProatSpacing.l)

                        Spacer()
                            .frame(minHeight: 40)
                    }
                    .frame(maxWidth: .infinity)
                    .frame(minHeight: 600)
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.proatBgBase)
            }
        }
    }

    private var rightSidebarView: some View {
        Group {
            if let transcription = selectedTranscription {
                TranscriptionInfoPanel(transcription: transcription)
                    .id(transcription.id)
            } else {
                VStack(spacing: ProatSpacing.s) {
                    Image(systemName: "info.circle")
                        .font(.system(size: 40))
                        .foregroundColor(.proatText3)
                    Text("Geen metadata")
                        .font(ProatFont.body)
                        .foregroundColor(.proatText2)
                }
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .background(Color.proatBgSunken)
            }
        }
    }

    private var allSelected: Bool {
        !displayedTranscriptions.isEmpty && displayedTranscriptions.allSatisfy { selectedTranscriptions.contains($0) }
    }

    private var selectionToolbar: some View {
        HStack(spacing: ProatSpacing.s) {
            if allSelected {
                Button("Niets selecteren") {
                    selectedTranscriptions.removeAll()
                }
                .buttonStyle(.plain)
                .font(ProatFont.klein)
                .foregroundColor(.proatText2)
            } else {
                Button("Alles selecteren") {
                    Task { await selectAllTranscriptions() }
                }
                .buttonStyle(.plain)
                .font(ProatFont.klein)
                .foregroundColor(.proatText2)
            }

            if !selectedTranscriptions.isEmpty {
                Rectangle().fill(Color.proatBorder)
                    .frame(width: 1, height: 16)

                Button(action: {
                    withAnimation(.smooth(duration: 0.3)) { isAnalysisPanelPresented = true }
                }) {
                    Image(systemName: "chart.bar.xaxis")
                        .font(.system(size: 14, weight: .regular))
                        .foregroundColor(.proatText2)
                }
                .buttonStyle(.plain)
                .help("Analyseren")

                Button(action: {
                    exportService.exportTranscriptionsToCSV(transcriptions: Array(selectedTranscriptions))
                }) {
                    Image(systemName: "square.and.arrow.up")
                        .font(.system(size: 14, weight: .regular))
                        .foregroundColor(.proatText2)
                }
                .buttonStyle(.plain)
                .help("Exporteren")

                Button(action: { showDeleteConfirmation = true }) {
                    Image(systemName: "trash")
                        .font(.system(size: 14, weight: .regular))
                        .foregroundColor(.proatError)
                }
                .buttonStyle(.plain)
                .help("Verwijderen")
            }

            Spacer()

            if !selectedTranscriptions.isEmpty {
                Text("\(selectedTranscriptions.count) geselecteerd")
                    .font(ProatFont.klein)
                    .fontWeight(.medium)
                    .foregroundColor(.proatText2)
            }
        }
        .padding(.horizontal, ProatSpacing.m)
        .padding(.vertical, ProatSpacing.xs)
        .background(
            Color.proatBgRaised
                .overlay(Rectangle().fill(Color.proatBorder).frame(height: 1), alignment: .top)
                .proatShadowRust()
        )
    }
    
    @MainActor
    private func loadInitialContent() async {
        isLoading = true
        defer { isLoading = false }

        do {
            lastTimestamp = nil
            let items = try modelContext.fetch(cursorQueryDescriptor())
            displayedTranscriptions = items
            lastTimestamp = items.last?.timestamp
            hasMoreContent = items.count == pageSize
        } catch {
            print("Error loading transcriptions: \(error)")
        }
    }

    @MainActor
    private func loadMoreContent() async {
        guard !isLoading, hasMoreContent, let lastTimestamp = lastTimestamp else { return }

        isLoading = true
        defer { isLoading = false }

        do {
            let newItems = try modelContext.fetch(cursorQueryDescriptor(after: lastTimestamp))
            displayedTranscriptions.append(contentsOf: newItems)
            self.lastTimestamp = newItems.last?.timestamp
            hasMoreContent = newItems.count == pageSize
        } catch {
            print("Error loading more transcriptions: \(error)")
        }
    }
    
    @MainActor
    private func resetPagination() {
        displayedTranscriptions = []
        lastTimestamp = nil
        hasMoreContent = true
        isLoading = false
    }

    private func performDeletion(for transcription: Transcription) {
        if let urlString = transcription.audioFileURL,
           let url = URL(string: urlString),
           FileManager.default.fileExists(atPath: url.path) {
            do {
                try FileManager.default.removeItem(at: url)
            } catch {
                print("Error deleting audio file: \(error.localizedDescription)")
            }
        }

        if selectedTranscription == transcription {
            selectedTranscription = nil
        }

        selectedTranscriptions.remove(transcription)
        modelContext.delete(transcription)
    }

    private func saveAndReload() async {
        do {
            try modelContext.save()
            NotificationCenter.default.post(name: .transcriptionDeleted, object: nil)
            await loadInitialContent()
        } catch {
            print("Error saving deletion: \(error.localizedDescription)")
            await loadInitialContent()
        }
    }

    private func deleteSelectedTranscriptions() {
        for transcription in selectedTranscriptions {
            performDeletion(for: transcription)
        }
        selectedTranscriptions.removeAll()

        Task {
            await saveAndReload()
        }
    }
    
    private func toggleSelection(_ transcription: Transcription) {
        if selectedTranscriptions.contains(transcription) {
            selectedTranscriptions.remove(transcription)
        } else {
            selectedTranscriptions.insert(transcription)
        }
    }

    private func selectAllTranscriptions() async {
        do {
            var allDescriptor = FetchDescriptor<Transcription>()

            if !searchText.isEmpty {
                allDescriptor.predicate = #Predicate<Transcription> { transcription in
                    transcription.text.localizedStandardContains(searchText) ||
                    (transcription.enhancedText?.localizedStandardContains(searchText) ?? false)
                }
            }

            allDescriptor.propertiesToFetch = [\.id]
            let allTranscriptions = try modelContext.fetch(allDescriptor)
            let visibleIds = Set(displayedTranscriptions.map { $0.id })

            await MainActor.run {
                selectedTranscriptions = Set(displayedTranscriptions)

                for transcription in allTranscriptions {
                    if !visibleIds.contains(transcription.id) {
                        selectedTranscriptions.insert(transcription)
                    }
                }
            }
        } catch {
            print("Error selecting all transcriptions: \(error)")
        }
    }
}
