import SwiftUI
import SwiftData

struct InlineHistoryView: View {
    @Environment(\.modelContext) private var modelContext
    @State private var searchText = ""
    @State private var expandedId: UUID?
    @State private var selectedTranscriptions: Set<Transcription> = []
    @State private var showDeleteConfirmation = false
    @State private var isPanelPresented = false
    @State private var panelMode: PanelMode = .info
    @State private var panelTranscriptionId: UUID?
    @State private var displayedTranscriptions: [Transcription] = []
    @State private var isLoading = false
    @State private var hasMoreContent = true
    @State private var lastTimestamp: Date?
    @State private var isViewCurrentlyVisible = false

    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
    }

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

    private var panelTranscription: Transcription? {
        guard let id = panelTranscriptionId else { return nil }
        return displayedTranscriptions.first { $0.id == id }
    }

    var body: some View {
        VStack(spacing: 0) {
            topBar
            Rectangle().fill(Color.proatBorder).frame(height: 1)

            if displayedTranscriptions.isEmpty && !isLoading {
                emptyStateView
            } else {
                cardListView
            }

            if !selectedTranscriptions.isEmpty {
                Rectangle().fill(Color.proatBorder).frame(height: 1)
                selectionBar
                    .transition(.move(edge: .bottom).combined(with: .opacity))
            }
        }
        .animation(.easeInOut(duration: 0.2), value: selectedTranscriptions.isEmpty)
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.proatBgBase)
        .overlay {
            Color.black.opacity(isPanelPresented ? 0.1 : 0)
                .ignoresSafeArea()
                .allowsHitTesting(isPanelPresented)
                .onTapGesture {
                    withAnimation(.smooth(duration: 0.3)) {
                        isPanelPresented = false
                        panelMode = .info
                    }
                }
                .animation(.smooth(duration: 0.3), value: isPanelPresented)
        }
        .overlay(alignment: .trailing) {
            if isPanelPresented {
                panelContent
                    .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: isPanelPresented)
        .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?")
        }
        .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()
                }
            }
        }
    }

    // MARK: - Top Bar

    private var topBar: some View {
        HStack(spacing: ProatSpacing.xs) {
            HStack(spacing: 6) {
                Image(systemName: "magnifyingglass")
                    .foregroundColor(.proatText3)
                    .font(.system(size: 12))
                TextField("Transcripties zoeken…", text: $searchText)
                    .textFieldStyle(.plain)
                    .font(ProatFont.body)
                    .foregroundColor(.proatText1)
            }
            .padding(.horizontal, ProatSpacing.xs)
            .padding(.vertical, 6)
            .background(
                Capsule()
                    .fill(Color.proatBgSunken)
                    .overlay(Capsule().stroke(Color.proatBorder, lineWidth: 1))
            )
            .frame(maxWidth: .infinity)
        }
        .padding(.horizontal, ProatSpacing.l)
        .padding(.vertical, ProatSpacing.xs)
    }

    private var selectionBar: some View {
        HStack(spacing: ProatSpacing.m) {
            Text("\(selectedTranscriptions.count) geselecteerd")
                .font(ProatFont.klein)
                .fontWeight(.medium)
                .foregroundColor(.proatText2)

            Spacer()

            Button(action: {
                panelMode = .analysis
                withAnimation(.smooth(duration: 0.3)) { isPanelPresented = true }
            }) {
                Label("Analyseren", systemImage: "chart.bar.xaxis")
                    .font(ProatFont.klein)
                    .fontWeight(.medium)
            }
            .buttonStyle(.plain)
            .foregroundColor(.proatText2)

            Button(action: {
                exportService.exportTranscriptionsToCSV(transcriptions: Array(selectedTranscriptions))
            }) {
                Label("Exporteren", systemImage: "square.and.arrow.up")
                    .font(ProatFont.klein)
                    .fontWeight(.medium)
            }
            .buttonStyle(.plain)
            .foregroundColor(.proatText2)

            Button(action: { showDeleteConfirmation = true }) {
                Label("Verwijderen", systemImage: "trash")
                    .font(ProatFont.klein)
                    .fontWeight(.medium)
            }
            .buttonStyle(.plain)
            .foregroundColor(.proatError)

            Rectangle().fill(Color.proatBorder)
                .frame(width: 1, height: 16)

            if allSelected {
                Button("Niets selecteren") {
                    selectedTranscriptions.removeAll()
                }
                .font(ProatFont.klein)
                .fontWeight(.medium)
                .buttonStyle(.plain)
                .foregroundColor(.proatText2)
            } else {
                Button("Alles selecteren") {
                    Task { await selectAllTranscriptions() }
                }
                .font(ProatFont.klein)
                .fontWeight(.medium)
                .buttonStyle(.plain)
                .foregroundColor(.proatText2)
            }
        }
        .padding(.horizontal, ProatSpacing.l)
        .padding(.vertical, ProatSpacing.xs)
        .background(
            Color.proatBgRaised
                .overlay(Rectangle().fill(Color.proatBorder).frame(height: 1), alignment: .top)
                .proatShadowRust()
        )
    }

    // MARK: - Empty State

    private var emptyStateView: some View {
        VStack(spacing: ProatSpacing.s) {
            Spacer()
            ProatBrandMark(size: 36, showCaption: false, opacity: 0.5)
            Image(systemName: "doc.text.magnifyingglass")
                .font(.system(size: 40))
                .foregroundColor(.proatTeal)
            Text(searchText.isEmpty ? "Nog geen transcripties" : "Geen resultaten gevonden")
                .font(ProatFont.sectie)
                .foregroundColor(.proatText1)
            Text(searchText.isEmpty ? "Je transcriptiehistorie verschijnt hier" : "Probeer een andere zoekterm")
                .font(ProatFont.body)
                .foregroundColor(.proatText2)
            Spacer()
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.proatBgBase)
    }

    // MARK: - Card List

    private var cardListView: some View {
        Form {
            ForEach(displayedTranscriptions) { transcription in
                Section {
                    HistoryCardRow(
                        transcription: transcription,
                        isExpanded: expandedId == transcription.id,
                        isChecked: selectedTranscriptions.contains(transcription),
                        onToggleExpand: {
                            withAnimation(.easeInOut(duration: 0.2)) {
                                expandedId = expandedId == transcription.id ? nil : transcription.id
                            }
                        },
                        onToggleCheck: { toggleSelection(transcription) },
                        onShowInfo: {
                            panelTranscriptionId = transcription.id
                            panelMode = .info
                            withAnimation(.smooth(duration: 0.3)) {
                                isPanelPresented = true
                            }
                        }
                    )
                }
            }

            if hasMoreContent {
                Section {
                    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, 4)
                    }
                    .buttonStyle(.plain)
                    .disabled(isLoading)
                }
            }
        }
        .formStyle(.grouped)
        .scrollContentBackground(.hidden)
        .background(Color.proatBgBase)
    }

    // MARK: - Sliding Panel

    @ViewBuilder
    private var panelContent: some View {
        switch panelMode {
        case .info:
            infoPanelContent
        case .analysis:
            PerformanceAnalysisPanelView(
                transcriptions: Array(selectedTranscriptions),
                onClose: {
                    withAnimation(.smooth(duration: 0.3)) {
                        isPanelPresented = false
                        panelMode = .info
                    }
                }
            )
            .id(selectedTranscriptions.count)
        }
    }

    private var infoPanelContent: some View {
        VStack(spacing: 0) {
            HStack(spacing: ProatSpacing.s) {
                Text("Info")
                    .font(ProatFont.sectie)
                    // "Info" is identiek in NL
                    .foregroundColor(.proatText1)
                Spacer()
                Button(action: {
                    withAnimation(.smooth(duration: 0.3)) {
                        isPanelPresented = false
                        panelMode = .info
                    }
                }) {
                    Image(systemName: "xmark")
                        .font(.system(size: 14, weight: .medium))
                        .foregroundColor(.proatText2)
                        .padding(6)
                        .background(Color.proatBgSunken)
                        .clipShape(Circle())
                }
                .buttonStyle(.plain)
            }
            .padding(.horizontal, ProatSpacing.l)
            .padding(.vertical, ProatSpacing.s)
            .background(Color.proatBgRaised)
            .overlay(Rectangle().fill(Color.proatBorder).frame(height: 1), alignment: .bottom)
            .zIndex(1)

            if let transcription = panelTranscription {
                TranscriptionInfoPanel(transcription: transcription)
                    .id(transcription.id)
            } else {
                Spacer()
            }
        }
    }

    // MARK: - Data Loading

    @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
    }

    // MARK: - Selection & Deletion

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

    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 expandedId == transcription.id {
            expandedId = nil
        }
        if panelTranscriptionId == transcription.id {
            panelTranscriptionId = nil
            isPanelPresented = false
        }

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

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

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

    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)")
        }
    }
}

// MARK: - History Card Row

private struct HistoryCardRow: View {
    let transcription: Transcription
    let isExpanded: Bool
    let isChecked: Bool
    let onToggleExpand: () -> Void
    let onToggleCheck: () -> Void
    let onShowInfo: () -> Void

    @State private var selectedTab: TranscriptionTab = .original

    private var displayText: String {
        switch selectedTab {
        case .original:
            return transcription.text
        case .enhanced:
            return transcription.enhancedText ?? ""
        }
    }

    private var hasAudioFile: Bool {
        if let urlString = transcription.audioFileURL,
           let url = URL(string: urlString),
           FileManager.default.fileExists(atPath: url.path) {
            return true
        }
        return false
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            HStack(spacing: ProatSpacing.xs) {
                Toggle("", isOn: Binding(
                    get: { isChecked },
                    set: { _ in onToggleCheck() }
                ))
                .toggleStyle(CircularCheckboxStyle())
                .labelsHidden()

                VStack(alignment: .leading, spacing: 4) {
                    Text(transcription.timestamp, format: .dateTime.month(.abbreviated).day().hour().minute())
                        .font(ProatFont.klein)
                        .fontWeight(.medium)
                        .foregroundColor(.proatText3)

                    if !isExpanded {
                        Text(transcription.enhancedText ?? transcription.text)
                            .font(ProatFont.body)
                            .lineLimit(2)
                            .foregroundColor(.proatText1)
                    }
                }

                Spacer()

                Image(systemName: "chevron.right")
                    .font(.caption2.weight(.semibold))
                    .foregroundColor(.proatText3)
                    .rotationEffect(.degrees(isExpanded ? 90 : 0))
                    .animation(.easeInOut(duration: 0.2), value: isExpanded)
            }
            .contentShape(Rectangle())
            .onTapGesture { onToggleExpand() }

            if isExpanded {
                expandedContent
                    .padding(.top, 10)
            }
        }
    }

    // MARK: - Expanded Content

    private var expandedContent: some View {
        VStack(alignment: .leading, spacing: ProatSpacing.xs) {
            // Tabs
            if transcription.enhancedText != nil {
                HStack(spacing: 4) {
                    ForEach(TranscriptionTab.allCases, id: \.self) { tab in
                        Button {
                            withAnimation(.easeInOut(duration: 0.15)) {
                                selectedTab = tab
                            }
                        } label: {
                            Text(tab.rawValue)
                                .font(ProatFont.klein)
                                .fontWeight(.medium)
                                .foregroundColor(selectedTab == tab ? .proatTeal : .proatText2)
                                .padding(.horizontal, ProatSpacing.xs)
                                .padding(.vertical, 4)
                                .background(
                                    Capsule()
                                        .fill(selectedTab == tab ? Color.proatTealTint : Color.clear)
                                )
                        }
                        .buttonStyle(.plain)
                    }
                    Spacer()
                }
            }

            ScrollView {
                Text(displayText)
                    .font(ProatFont.body)
                    .foregroundColor(.proatText1)
                    .textSelection(.enabled)
                    .frame(maxWidth: .infinity, alignment: .leading)
            }
            .frame(maxHeight: 350)
            .overlay(alignment: .bottomTrailing) {
                CopyIconButton(textToCopy: displayText)
                    .padding(ProatSpacing.xs)
            }

            if hasAudioFile, let urlString = transcription.audioFileURL,
               let url = URL(string: urlString) {
                Rectangle().fill(Color.proatBorder).frame(height: 1)
                AudioPlayerView(url: url, transcription: transcription, onInfoTap: onShowInfo)
                .padding(.vertical, 4)
            } else {
                HStack {
                    Spacer()
                    Button(action: onShowInfo) {
                        Image(systemName: "info.circle")
                            .font(.system(size: 14, weight: .medium))
                            .foregroundColor(.proatText2)
                    }
                    .buttonStyle(.plain)
                    .help("Details bekijken")
                }
            }
        }
    }

}

