import SwiftUI

struct SearchView: View {
    @State private var viewModel = SearchViewModel()

    // Navigation destination after fetching the full object
    enum Destination {
        case page(PageDTO)
        case book(BookDTO)
        case shelf(ShelfDTO)
    }

    @State private var destination: Destination? = nil
    @State private var isLoadingDestination = false
    @State private var navigationActive = false
    @State private var loadError: BookStackError? = nil

    @FocusState private var searchFocused: Bool

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                // Persistent search bar
                HStack(spacing: 10) {
                    Image(systemName: "magnifyingglass")
                        .foregroundStyle(.secondary)
                    TextField(L("search.prompt"), text: $viewModel.query)
                        .focused($searchFocused)
                        .autocorrectionDisabled()
                        .textInputAutocapitalization(.never)
                        .submitLabel(.search)
                        .onSubmit { viewModel.onQueryChanged() }
                        .onChange(of: viewModel.query) { viewModel.onQueryChanged() }
                    if !viewModel.query.isEmpty {
                        Button {
                            viewModel.query = ""
                            viewModel.results = []
                            searchFocused = false
                        } label: {
                            Image(systemName: "xmark.circle.fill")
                                .foregroundStyle(.secondary)
                        }
                        .buttonStyle(.plain)
                    }
                }
                .padding(.horizontal, 12)
                .padding(.vertical, 9)
                .background(Color(.secondarySystemBackground), in: RoundedRectangle(cornerRadius: 12))
                .padding(.horizontal, 16)
                .padding(.top, 8)
                .padding(.bottom, 8)

                Divider()

                Group {
                    if viewModel.query.isEmpty {
                        recentSearchesView
                    } else if viewModel.isSearching {
                        LoadingView(message: L("search.loading"))
                    } else if viewModel.results.isEmpty {
                        ContentUnavailableView.search(text: viewModel.query)
                    } else {
                        resultsList
                    }
                }
            }
            .navigationTitle(L("search.title"))
            .navigationBarTitleDisplayMode(.inline)
            .task { await viewModel.loadAvailableTags() }
            .toolbar {
                ToolbarItem(placement: .topBarTrailing) {
                    filterMenu
                }
            }
            .navigationDestination(isPresented: $navigationActive) {
                switch destination {
                case .page(let page):   PageReaderView(page: page)
                case .book(let book):   BookDetailView(book: book)
                case .shelf(let shelf): BooksInShelfView(shelf: shelf)
                case nil:               EmptyView()
                }
            }
            .overlay {
                if isLoadingDestination {
                    ZStack {
                        Color.black.opacity(0.15).ignoresSafeArea()
                        ProgressView(L("search.opening"))
                            .padding(20)
                            .background(.regularMaterial, in: RoundedRectangle(cornerRadius: 14))
                    }
                }
            }
            .alert(L("search.error.title"), isPresented: Binding(
                get: { loadError != nil },
                set: { if !$0 { loadError = nil } }
            )) {
                Button(L("common.ok"), role: .cancel) {}
            } message: {
                Text(loadError?.errorDescription ?? L("common.error"))
            }
        }
    }

    // MARK: - Results List

    private var resultsList: some View {
        List {
            if let error = viewModel.error {
                ErrorBanner(error: error) {
                    viewModel.onFilterChanged()
                }
                .listRowBackground(Color.clear)
                .listRowSeparator(.hidden)
            }
            ForEach(viewModel.results) { result in
                Button {
                    Task { await open(result) }
                } label: {
                    SearchResultRow(result: result)
                }
                .foregroundStyle(.primary)
            }
        }
        .listStyle(.insetGrouped)
        .animation(.easeInOut, value: viewModel.results.map(\.id))
    }

    // MARK: - Open result

    private func open(_ result: SearchResultDTO) async {
        isLoadingDestination = true
        loadError = nil
        do {
            switch result.type {
            case .page:
                let page = try await BookStackAPI.shared.fetchPage(id: result.id)
                destination = .page(page)
            case .book:
                let book = try await BookStackAPI.shared.fetchBook(id: result.id)
                destination = .book(book)
            case .shelf:
                let shelfDetail = try await BookStackAPI.shared.fetchShelf(id: result.id)
                // Build a ShelfDTO from the ShelfBooksResponse for BooksInShelfView
                let shelf = ShelfDTO(
                    id: shelfDetail.id,
                    name: shelfDetail.name,
                    slug: "",
                    description: "",
                    createdAt: Date(),
                    updatedAt: Date(),
                    cover: nil
                )
                destination = .shelf(shelf)
            case .chapter:
                // Navigate to the chapter's parent book
                let chapter = try await BookStackAPI.shared.fetchChapter(id: result.id)
                let book = try await BookStackAPI.shared.fetchBook(id: chapter.bookId)
                destination = .book(book)
            }
            navigationActive = true
        } catch let e as BookStackError {
            loadError = e
        } catch {
            loadError = .unknown(error.localizedDescription)
        }
        isLoadingDestination = false
    }

    // MARK: - Recent Searches

    private var recentSearchesView: some View {
        Group {
            if viewModel.recentSearches.isEmpty {
                EmptyStateView(
                    systemImage: "magnifyingglass",
                    title: L("search.empty.title"),
                    message: L("search.empty.message")
                )
            } else {
                List {
                    Section {
                        ForEach(viewModel.recentSearches, id: \.self) { recent in
                            Button {
                                viewModel.query = recent
                                viewModel.onQueryChanged()
                            } label: {
                                Label(recent, systemImage: "clock")
                                    .foregroundStyle(.primary)
                            }
                        }
                    } header: {
                        HStack {
                            Text(L("search.recent"))
                            Spacer()
                            Button(L("search.recent.clear")) {
                                viewModel.clearRecentSearches()
                            }
                            .font(.footnote)
                        }
                    }
                }
                .listStyle(.insetGrouped)
            }
        }
    }

    // MARK: - Filter Menu

    private var hasActiveFilter: Bool {
        viewModel.selectedTypeFilter != nil || viewModel.selectedTagFilter != nil
    }

    private var filterMenu: some View {
        Menu {
            // Type filter
            Section(L("search.filter.type")) {
                Button {
                    viewModel.selectedTypeFilter = nil
                    viewModel.onFilterChanged()
                } label: {
                    Label(L("search.filter.all"),
                          systemImage: viewModel.selectedTypeFilter == nil ? "checkmark" : "square")
                }
                ForEach(SearchResultDTO.ContentType.allCases, id: \.self) { type in
                    Button {
                        viewModel.selectedTypeFilter = (viewModel.selectedTypeFilter == type) ? nil : type
                        viewModel.onFilterChanged()
                    } label: {
                        Label(type.displayName,
                              systemImage: viewModel.selectedTypeFilter == type ? "checkmark" : type.systemImage)
                    }
                }
            }

            // Tag filter
            if !viewModel.availableTags.isEmpty {
                Section(L("search.filter.tag")) {
                    if viewModel.selectedTagFilter != nil {
                        Button {
                            viewModel.selectedTagFilter = nil
                            viewModel.onFilterChanged()
                        } label: {
                            Label(L("search.filter.tag.clear"), systemImage: "xmark.circle")
                        }
                    }
                    let uniqueNames = Array(Set(viewModel.availableTags.map(\.name))).sorted()
                    ForEach(uniqueNames.prefix(15), id: \.self) { name in
                        Button {
                            viewModel.selectedTagFilter = (viewModel.selectedTagFilter == name) ? nil : name
                            viewModel.onFilterChanged()
                        } label: {
                            Label(name, systemImage: viewModel.selectedTagFilter == name ? "checkmark" : "tag")
                        }
                    }
                }
            }
        } label: {
            Image(systemName: hasActiveFilter
                  ? "line.3.horizontal.decrease.circle.fill"
                  : "line.3.horizontal.decrease.circle")
        }
        .accessibilityLabel(L("search.filter"))
    }
}

// MARK: - Search Result Row

struct SearchResultRow: View {
    let result: SearchResultDTO

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack {
                Image(systemName: result.type.systemImage)
                    .font(.footnote)
                    .foregroundStyle(.blue)
                    .frame(width: 18)
                    .accessibilityHidden(true)

                Text(result.name)
                    .font(.body.weight(.medium))

                Spacer()

                Text(result.type.displayName)
                    .font(.caption)
                    .foregroundStyle(.secondary)
                    .padding(.horizontal, 6)
                    .padding(.vertical, 2)
                    .background(Color(.secondarySystemBackground), in: Capsule())
            }

            if let preview = result.preview, !preview.isEmpty {
                Text(preview)
                    .font(.footnote)
                    .foregroundStyle(.secondary)
                    .lineLimit(2)
                    .padding(.leading, 26)
            }

            if !result.tags.isEmpty {
                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 4) {
                        ForEach(result.tags) { tag in
                            Text(tag.value.isEmpty ? tag.name : "\(tag.name): \(tag.value)")
                                .font(.caption2.weight(.medium))
                                .foregroundStyle(.secondary)
                                .padding(.horizontal, 6)
                                .padding(.vertical, 2)
                                .background(Color(.tertiarySystemBackground), in: Capsule())
                                .overlay(Capsule().strokeBorder(Color(.separator), lineWidth: 0.5))
                        }
                    }
                    .padding(.leading, 26)
                }
            }
        }
        .padding(.vertical, 4)
        .accessibilityLabel("\(result.type.displayName): \(result.name)")
        .accessibilityHint(result.preview ?? "")
    }
}

#Preview {
    SearchView()
}
