//
//  ChatView.swift
//  Confab
//
//  Main chat interface
//
// 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 ChatView: View {
    @Environment(ChatViewModel.self) var viewModel
    let onModelSelect: () -> Void
    let onProviderChange: (Settings.Provider) -> Void

    var body: some View {
        @Bindable var viewModel = viewModel
        VStack(spacing: 0) {
            // Header
            HeaderView(
                provider: viewModel.currentProvider,
                model: viewModel.selectedModel,
                onModelSelect: onModelSelect,
                onProviderChange: onProviderChange,
                conversationName: viewModel.currentConversationName,
                hasUnsavedChanges: viewModel.hasUnsavedChanges,
                onQuickSave: viewModel.quickSave
            )

            // Messages
            ScrollViewReader { proxy in
                ScrollView {
                    LazyVStack(alignment: .leading, spacing: 12) {
                        ForEach(viewModel.messages) { message in
                            MessageRow(message: message, viewModel: viewModel)
                                .id(message.id)
                        }

                        // Processing indicator
                        if viewModel.isGenerating && viewModel.messages.last?.isStreaming != true {
                            ProcessingIndicator(toolActivity: viewModel.currentToolActivity)
                                .padding(.horizontal)
                        }

                        // Invisible bottom anchor for auto-scroll
                        Color.clear
                            .frame(height: 1)
                            .id("bottom")
                    }
                    .padding()
                }
                .background(Color.confabBackground)
                .onChange(of: viewModel.messages.count) {
                    withAnimation {
                        proxy.scrollTo("bottom", anchor: .bottom)
                    }
                }
                .onChange(of: viewModel.messages.last?.content) {
                    // Auto-scroll as streaming content arrives
                    if viewModel.isGenerating {
                        proxy.scrollTo("bottom", anchor: .bottom)
                    }
                }
            }

            // Input bar
            InputBar(
                text: $viewModel.inputText,
                isGenerating: viewModel.isGenerating,
                onlineMode: viewModel.onlineMode,
                onSend: viewModel.sendMessage,
                onCancel: viewModel.cancelGeneration,
                onToggleOnline: {
                    viewModel.onlineMode.toggle()
                    SettingsService.shared.onlineMode = viewModel.onlineMode
                }
            )

            // Footer
            FooterView(
                stats: viewModel.sessionStats,
                conversationName: viewModel.currentConversationName,
                hasUnsavedChanges: viewModel.hasUnsavedChanges,
                onQuickSave: viewModel.quickSave,
                onlineMode: viewModel.onlineMode,
                mcpEnabled: viewModel.mcpEnabled
            )
        }
        .background(Color.confabBackground)
        .sheet(isPresented: $viewModel.showShortcuts) {
            ShortcutsView()
        }
        .sheet(isPresented: $viewModel.showSkills) {
            AgentSkillsView()
        }
        .sheet(isPresented: $viewModel.showJarvis) {
            JarvisView()
        }
        .sheet(item: Binding(
            get: { MCPService.shared.pendingBashCommand },
            set: { _ in }
        )) { pending in
            BashApprovalSheet(
                pending: pending,
                onApprove: { forSession in MCPService.shared.approvePendingBashCommand(forSession: forSession) },
                onDeny: { MCPService.shared.denyPendingBashCommand() }
            )
        }
        .sheet(item: Binding(
            get: { MCPService.shared.pendingPersonalDataAction },
            set: { _ in }
        )) { pending in
            PersonalDataApprovalSheet(
                pending: pending,
                onApprove: { forSession in MCPService.shared.approvePendingPersonalDataAction(forSession: forSession) },
                onDeny: { MCPService.shared.denyPendingPersonalDataAction() }
            )
        }
        .sheet(item: Binding(
            get: { GitSyncService.shared.pendingGitConflict },
            set: { _ in }
        )) { pending in
            GitSyncConflictSheet(
                pending: pending,
                onFixForMe: { await GitSyncService.shared.autoResolveUntrackedConflict(pending) },
                onFixMyself: { GitSyncService.shared.showManualFixInstructions(for: pending) },
                onDismiss: { GitSyncService.shared.dismissPendingGitConflict() }
            )
        }
        .sheet(item: Binding(
            get: { GitSyncService.shared.pendingManualFixInstructions },
            set: { _ in }
        )) { pending in
            GitSyncManualFixSheet(
                files: pending.files,
                syncPath: SettingsService.shared.syncLocalPath,
                onDone: { GitSyncService.shared.dismissManualFixInstructions() }
            )
        }
    }
}

struct ProcessingIndicator: View {
    /// Current tool round's status (e.g. "🔧 Calling: read_file"), replaced in place each round
    /// rather than the chat accumulating a new row per round — see ChatViewModel.currentToolActivity.
    let toolActivity: String?
    @State private var animating = false
    @State private var thinkingText = ThinkingVerbs.random()

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            HStack(spacing: 8) {
                Text(thinkingText)
                    .font(.system(size: 14, weight: .medium))
                    .foregroundColor(.confabSecondary)

                HStack(spacing: 4) {
                    ForEach(0..<3) { index in
                        Circle()
                            .fill(Color.confabSecondary)
                            .frame(width: 6, height: 6)
                            .scaleEffect(animating ? 1.0 : 0.5)
                            .animation(
                                .easeInOut(duration: 0.6)
                                    .repeatForever()
                                    .delay(Double(index) * 0.2),
                                value: animating
                            )
                    }
                }
            }

            if let toolActivity {
                Text(toolActivity)
                    .font(.system(size: 12))
                    .foregroundColor(.confabSecondary.opacity(0.75))
                    .transition(.opacity)
            }
        }
        .animation(.easeInOut(duration: 0.15), value: toolActivity)
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
        .background(Color.confabSecondary.opacity(0.05))
        .cornerRadius(8)
        .onAppear {
            animating = true
        }
    }
}

#Preview {
    ChatView(onModelSelect: {}, onProviderChange: { _ in })
        .environment(ChatViewModel())
}
