//
//  ModelSelectorView.swift
//  oAI
//
//  Model selection screen
//
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2026 Rune Olsen
//
// This file is part of oAI.
//
// oAI is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// oAI is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
// Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with oAI. If not, see <https://www.gnu.org/licenses/>.


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 keyboardIndex: Int = -1
    @State private var sortOrder: ModelSortOrder = .default
    @State private var selectedInfoModel: ModelInfo? = nil

    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

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

        switch sortOrder {
        case .default:
            return filtered
        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()

                    // 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,
                                onSelect: { onSelect(model) },
                                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: 600, 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)
            }
            .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)
    }
}

// MARK: - Model Row

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

    var body: some View {
        HStack(alignment: .top, spacing: 8) {
            // Selectable main content
            VStack(alignment: .leading, spacing: 6) {
                HStack {
                    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 + 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) }
                }

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