//
//  ModelSelectorView.swift
//  Confab
//
//  Model selection screen
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
//
// This file is part of Confab.
//
// Confab is licensed under the PolyForm Noncommercial License 1.0.0.
// You may use, study, modify, and share it for any noncommercial
// purpose. Commercial use — including selling Confab or any part of
// it, standalone or bundled into another product or service —
// requires a separate commercial license from the copyright holder.
//
// See the LICENSE file or
// <https://polyformproject.org/licenses/noncommercial/1.0.0> for
// the full license text. For commercial licensing, contact Rune
// Olsen via <https://confab.no>.


import SwiftUI

struct ModelSelectorView: View {
    let models: [ModelInfo]
    let selectedModel: ModelInfo?
    let onSelect: (ModelInfo) -> Void

    @Environment(\.dismiss) var dismiss
    @State private var searchText = ""
    @State private var filterVision = false
    @State private var filterTools = false
    @State private var filterOnline = false
    @State private var filterImageGen = false
    @State private var filterThinking = false
    @State private var filterFavorites = false
    @State private var selectedCategory: ModelCategory? = nil
    @State private var showCategoryPicker = false
    @State private var keyboardIndex: Int = -1
    @State private var sortOrder: ModelSortOrder = .default
    @State private var selectedInfoModel: ModelInfo? = nil
    @Bindable private var settings = SettingsService.shared

    private var categoriesWithModels: Set<ModelCategory> {
        Set(models.flatMap(\.categories))
    }

    private var filteredModels: [ModelInfo] {
        let q = searchText.lowercased()
        let filtered = models.filter { model in
            let matchesSearch = searchText.isEmpty ||
                model.name.lowercased().contains(q) ||
                model.id.lowercased().contains(q) ||
                model.description?.lowercased().contains(q) == true

            let matchesVision = !filterVision || model.capabilities.vision
            let matchesTools = !filterTools || model.capabilities.tools
            let matchesOnline = !filterOnline || model.capabilities.online
            let matchesImageGen = !filterImageGen || model.capabilities.imageGeneration
            let matchesThinking = !filterThinking || model.capabilities.thinking
            let matchesFavorites = !filterFavorites || settings.favoriteModelIds.contains(model.id)
            let matchesCategory = selectedCategory == nil || model.categories.contains(selectedCategory!)

            return matchesSearch && matchesVision && matchesTools && matchesOnline && matchesImageGen && matchesThinking && matchesFavorites && matchesCategory
        }

        let favIds = settings.favoriteModelIds
        switch sortOrder {
        case .default:
            return filtered.sorted { a, b in
                let aFav = favIds.contains(a.id)
                let bFav = favIds.contains(b.id)
                if aFav != bFav { return aFav }
                return false
            }
        case .priceLowHigh:
            return filtered.sorted { $0.pricing.prompt < $1.pricing.prompt }
        case .priceHighLow:
            return filtered.sorted { $0.pricing.prompt > $1.pricing.prompt }
        case .contextHighLow:
            return filtered.sorted { $0.contextLength > $1.contextLength }
        }
    }

    var body: some View {
        NavigationStack {
            VStack(spacing: 0) {
                // Search bar
                TextField("Search models...", text: $searchText)
                    .textFieldStyle(.roundedBorder)
                    .padding()
                    .onChange(of: searchText) {
                        keyboardIndex = -1
                    }

                // Filters + Sort
                HStack(spacing: 12) {
                    FilterToggle(isOn: $filterVision, icon: "\u{1F441}\u{FE0F}", label: "Vision")
                    FilterToggle(isOn: $filterTools, icon: "\u{1F527}", label: "Tools")
                    FilterToggle(isOn: $filterOnline, icon: "\u{1F310}", label: "Online")
                    FilterToggle(isOn: $filterImageGen, icon: "\u{1F3A8}", label: "Image Gen")
                    FilterToggle(isOn: $filterThinking, icon: "\u{1F9E0}", label: "Thinking")

                    Spacer()

                    // Category picker (only shown when at least one category has models)
                    if !categoriesWithModels.isEmpty {
                    Button(action: { showCategoryPicker.toggle() }) {
                        HStack(spacing: 4) {
                            if let cat = selectedCategory {
                                Circle().fill(cat.color).frame(width: 7, height: 7)
                                Text(LocalizedStringKey(cat.rawValue))
                            } else {
                                Image(systemName: "tag")
                                Text("Category")
                            }
                        }
                        .font(.caption)
                        .padding(.horizontal, 10)
                        .padding(.vertical, 6)
                        .background(selectedCategory != nil ? selectedCategory!.color.opacity(0.18) : Color.gray.opacity(0.1))
                        .foregroundColor(selectedCategory != nil ? selectedCategory!.color : .secondary)
                        .cornerRadius(6)
                        .overlay(
                            RoundedRectangle(cornerRadius: 6)
                                .strokeBorder(selectedCategory != nil ? selectedCategory!.color.opacity(0.4) : Color.clear, lineWidth: 1)
                        )
                    }
                    .buttonStyle(.plain)
                    .help("Filter by category")
                    .popover(isPresented: $showCategoryPicker, arrowEdge: .bottom) {
                        CategoryPickerPopover(
                            categoriesWithModels: categoriesWithModels,
                            selectedCategory: $selectedCategory,
                            onSelect: { keyboardIndex = -1 }
                        )
                    }
                    } // end if !categoriesWithModels.isEmpty

                    // Favorites filter star
                    Button(action: { filterFavorites.toggle(); keyboardIndex = -1 }) {
                        Image(systemName: filterFavorites ? "star.fill" : "star")
                            .font(.caption)
                            .padding(.horizontal, 10)
                            .padding(.vertical, 6)
                            .background(filterFavorites ? Color.yellow.opacity(0.25) : Color.gray.opacity(0.1))
                            .foregroundColor(filterFavorites ? .yellow : .secondary)
                            .cornerRadius(6)
                    }
                    .buttonStyle(.plain)
                    .help("Show favorites only")

                    // Sort menu
                    Menu {
                        ForEach(ModelSortOrder.allCases, id: \.rawValue) { order in
                            Button {
                                sortOrder = order
                                keyboardIndex = -1
                            } label: {
                                if sortOrder == order {
                                    Label(order.label, systemImage: "checkmark")
                                } else {
                                    Text(order.label)
                                }
                            }
                        }
                    } label: {
                        HStack(spacing: 4) {
                            Image(systemName: "arrow.up.arrow.down")
                            Text("Sort")
                        }
                        .font(.caption)
                        .padding(.horizontal, 10)
                        .padding(.vertical, 6)
                        .background(sortOrder != .default ? Color.blue.opacity(0.2) : Color.gray.opacity(0.1))
                        .foregroundColor(sortOrder != .default ? .blue : .secondary)
                        .cornerRadius(6)
                    }
                    .menuStyle(.borderlessButton)
                    .fixedSize()
                }
                .padding(.horizontal)
                .padding(.bottom, 12)

                Divider()

                // Model list
                if filteredModels.isEmpty {
                    ContentUnavailableView(
                        "No Models Found",
                        systemImage: "magnifyingglass",
                        description: Text("Try adjusting your search or filters")
                    )
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                } else {
                    ScrollViewReader { proxy in
                        List(Array(filteredModels.enumerated()), id: \.element.id) { index, model in
                            ModelRowView(
                                model: model,
                                isSelected: model.id == selectedModel?.id,
                                isKeyboardHighlighted: index == keyboardIndex,
                                isFavorite: settings.favoriteModelIds.contains(model.id),
                                onSelect: { onSelect(model) },
                                onFavorite: { settings.toggleFavoriteModel(model.id) },
                                onInfo: { selectedInfoModel = model }
                            )
                            .id(model.id)
                        }
                        .listStyle(.plain)
                        .onChange(of: keyboardIndex) { _, newIndex in
                            if newIndex >= 0 && newIndex < filteredModels.count {
                                withAnimation {
                                    proxy.scrollTo(filteredModels[newIndex].id, anchor: .center)
                                }
                            }
                        }
                    }
                }
            }
            .frame(minWidth: 740, minHeight: 500)
            .navigationTitle("Select Model")
            #if os(macOS)
            .onKeyPress(.downArrow) {
                if keyboardIndex < filteredModels.count - 1 {
                    keyboardIndex += 1
                }
                return .handled
            }
            .onKeyPress(.upArrow) {
                if keyboardIndex > 0 {
                    keyboardIndex -= 1
                } else if keyboardIndex == -1 && !filteredModels.isEmpty {
                    keyboardIndex = 0
                }
                return .handled
            }
            .onKeyPress(.return) {
                if keyboardIndex >= 0 && keyboardIndex < filteredModels.count {
                    onSelect(filteredModels[keyboardIndex])
                    return .handled
                }
                return .ignored
            }
            #endif
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") {
                        dismiss()
                    }
                }
            }
            .onAppear {
                if let selected = selectedModel,
                   let index = filteredModels.firstIndex(where: { $0.id == selected.id }) {
                    keyboardIndex = index
                }
            }
            .sheet(item: $selectedInfoModel) { model in
                ModelInfoView(model: model)
            }
        }
    }
}

// MARK: - Sort Order

enum ModelSortOrder: String, CaseIterable {
    case `default`
    case priceLowHigh
    case priceHighLow
    case contextHighLow

    var label: LocalizedStringKey {
        switch self {
        case .default: return "Default"
        case .priceLowHigh: return "Price: Low to High"
        case .priceHighLow: return "Price: High to Low"
        case .contextHighLow: return "Context: High to Low"
        }
    }
}

// MARK: - Filter Toggle

struct FilterToggle: View {
    @Binding var isOn: Bool
    let icon: String
    let label: LocalizedStringKey

    var body: some View {
        Button(action: { isOn.toggle() }) {
            HStack(spacing: 4) {
                Text(icon)
                Text(label)
                    .lineLimit(1)
            }
            .font(.caption)
            .padding(.horizontal, 10)
            .padding(.vertical, 6)
            .background(isOn ? Color.blue.opacity(0.2) : Color.gray.opacity(0.1))
            .foregroundColor(isOn ? .blue : .secondary)
            .cornerRadius(6)
        }
        .buttonStyle(.plain)
        .fixedSize()
    }
}

// MARK: - Category Picker Popover

struct CategoryPickerPopover: View {
    let categoriesWithModels: Set<ModelCategory>
    @Binding var selectedCategory: ModelCategory?
    let onSelect: () -> Void

    private let columns = [GridItem(.adaptive(minimum: 130), spacing: 8)]

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                Text("Filter by Category")
                    .font(.caption.weight(.semibold))
                    .foregroundStyle(.secondary)
                Spacer()
                if selectedCategory != nil {
                    Button("Clear") {
                        selectedCategory = nil
                        onSelect()
                    }
                    .font(.caption)
                    .buttonStyle(.plain)
                    .foregroundStyle(.blue)
                }
            }

            LazyVGrid(columns: columns, spacing: 8) {
                ForEach(ModelCategory.allCases.filter { categoriesWithModels.contains($0) }, id: \.rawValue) { cat in
                    let isSelected = selectedCategory == cat
                    Button {
                        selectedCategory = isSelected ? nil : cat
                        onSelect()
                    } label: {
                        HStack(spacing: 6) {
                            Image(systemName: cat.systemImage)
                                .font(.caption)
                                .frame(width: 14)
                            Text(LocalizedStringKey(cat.rawValue))
                                .font(.caption)
                            Spacer()
                        }
                        .padding(.horizontal, 10)
                        .padding(.vertical, 7)
                        .background(isSelected ? cat.color.opacity(0.18) : Color.gray.opacity(0.08))
                        .foregroundColor(isSelected ? cat.color : .primary)
                        .cornerRadius(6)
                        .overlay(
                            RoundedRectangle(cornerRadius: 6)
                                .strokeBorder(isSelected ? cat.color.opacity(0.45) : Color.clear, lineWidth: 1)
                        )
                    }
                    .buttonStyle(.plain)
                }
            }
        }
        .padding(14)
        .frame(minWidth: 360)
    }
}

// MARK: - Model Row

struct ModelRowView: View {
    let model: ModelInfo
    let isSelected: Bool
    var isKeyboardHighlighted: Bool = false
    var isFavorite: Bool = false
    let onSelect: () -> Void
    var onFavorite: (() -> Void)? = nil
    let onInfo: () -> Void

    var body: some View {
        HStack(alignment: .top, spacing: 8) {
            // Selectable main content
            VStack(alignment: .leading, spacing: 6) {
                HStack(spacing: 6) {
                    if let onFavorite {
                        Button(action: onFavorite) {
                            Image(systemName: isFavorite ? "star.fill" : "star")
                                .font(.system(size: 13))
                                .foregroundColor(isFavorite ? .yellow : .secondary)
                        }
                        .buttonStyle(.plain)
                        .help(isFavorite ? "Remove from favorites" : "Add to favorites")
                    }
                    Text(model.name)
                        .font(.headline)
                        .foregroundColor(isSelected ? .blue : .primary)

                    if isSelected {
                        Image(systemName: "checkmark.circle.fill")
                            .foregroundColor(.blue)
                    }
                }

                Text(model.id)
                    .font(.caption)
                    .foregroundColor(.secondary)

                if let description = model.description {
                    Text(description)
                        .font(.caption)
                        .foregroundColor(.secondary)
                        .lineLimit(2)
                }

                HStack(spacing: 12) {
                    Label(model.contextLengthDisplay, systemImage: "text.alignleft")
                    Label(model.promptPriceDisplay + "/1M", systemImage: "dollarsign.circle")
                }
                .font(.caption2)
                .foregroundColor(.secondary)
            }
            .frame(maxWidth: .infinity, alignment: .leading)
            .contentShape(Rectangle())
            .onTapGesture { onSelect() }

            // Right side: capabilities + category dots + info button
            VStack(alignment: .trailing, spacing: 6) {
                // Capability icons
                HStack(spacing: 4) {
                    if model.capabilities.vision { Text("\u{1F441}\u{FE0F}").font(.caption) }
                    if model.capabilities.tools { Text("\u{1F527}").font(.caption) }
                    if model.capabilities.online { Text("\u{1F310}").font(.caption) }
                    if model.capabilities.imageGeneration { Text("\u{1F3A8}").font(.caption) }
                    if model.capabilities.thinking { Text("\u{1F9E0}").font(.caption) }
                }

                // Category dots
                if !model.categories.isEmpty {
                    HStack(spacing: 3) {
                        ForEach(model.categories, id: \.rawValue) { cat in
                            Circle()
                                .fill(cat.color)
                                .frame(width: 7, height: 7)
                                .help(cat.rawValue)
                        }
                    }
                }

                // Info button
                Button(action: onInfo) {
                    Image(systemName: "info.circle")
                        .font(.caption)
                        .foregroundColor(.secondary)
                        .frame(width: 20, height: 20)
                }
                .buttonStyle(.plain)
                .help("Show model info")
            }
            .padding(.top, 2)
        }
        .padding(.vertical, 6)
        .padding(.horizontal, isKeyboardHighlighted ? 4 : 0)
        .background(
            isKeyboardHighlighted
                ? RoundedRectangle(cornerRadius: 6).fill(Color.accentColor.opacity(0.15))
                : nil
        )
    }
}

#Preview {
    ModelSelectorView(
        models: ModelInfo.mockModels,
        selectedModel: ModelInfo.mockModels.first,
        onSelect: { _ in }
    )
}
