import * as vscode from 'vscode';
import { AbysiusApi, ChatMessage, ChatRequest } from './api';

export interface ChatHistoryMessage {
    id: string;
    role: 'user' | 'assistant';
    content: string;
    timestamp: number;
}

export class ChatPanel implements vscode.WebviewViewProvider {
    private _view?: vscode.WebviewView;
    private _api: AbysiusApi;
    private _messages: ChatHistoryMessage[] = [];
    private _currentStreamAbort?: AbortController;
    private _extensionUri: vscode.Uri;

    constructor(extensionUri: vscode.Uri, api: AbysiusApi) {
        this._extensionUri = extensionUri;
        this._api = api;
    }

    resolveWebviewView(
        webviewView: vscode.WebviewView,
        context: vscode.WebviewViewResolveContext,
        _token: vscode.CancellationToken
    ) {
        this._view = webviewView;

        webviewView.webview.options = {
            enableScripts: true,
            localResourceRoots: [this._extensionUri]
        };

        webviewView.webview.html = this._getHtmlForWebview(webviewView.webview);

        webviewView.webview.onDidReceiveMessage(
            async (message) => {
                switch (message.type) {
                    case 'sendMessage':
                        await this._handleUserMessage(message.text);
                        break;
                    case 'cancel':
                        this._currentStreamAbort?.abort();
                        break;
                    case 'clear':
                        this.clear();
                        break;
                    case 'ready':
                        this._postMessage({ type: 'history', messages: this._messages });
                        break;
                    case 'insertCode':
                        this._insertCodeIntoEditor(message.code);
                        break;
                    case 'copyCode':
                        vscode.env.clipboard.writeText(message.code);
                        break;
                }
            }
        );

        webviewView.onDidDispose(() => {
            this._view = undefined;
        });
    }

    show(): void {
        if (this._view) {
            this._view.show(true);
        } else {
            vscode.commands.executeCommand('abysius.chatPanel.focus');
        }
    }

    clear(): void {
        this._messages = [];
        this._postMessage({ type: 'clear' });
    }

    private async _handleUserMessage(text: string): Promise<void> {
        const userMsg: ChatHistoryMessage = {
            id: this._generateId(),
            role: 'user',
            content: text,
            timestamp: Date.now()
        };
        this._messages.push(userMsg);
        this._postMessage({ type: 'userMessage', message: userMsg });

        // Gather context from active editor
        const context = this._getEditorContext();
        
        const chatMessages: ChatMessage[] = [
            {
                role: 'system',
                content: this._buildSystemPrompt(context)
            }
        ];

        // Add recent message history
        const recentMessages = this._messages.slice(-10);
        for (const msg of recentMessages) {
            chatMessages.push({
                role: msg.role,
                content: msg.content
            });
        }

        const request: ChatRequest = {
            messages: chatMessages,
            temperature: 0.7,
            max_tokens: 4096
        };

        const assistantId = this._generateId();
        this._postMessage({ 
            type: 'assistantStart', 
            id: assistantId 
        });

        try {
            this._currentStreamAbort = new AbortController();
            const stream = this._api.streamChat(request, this._currentStreamAbort.signal);

            let fullResponse = '';
            for await (const chunk of stream) {
                fullResponse += chunk;
                this._postMessage({
                    type: 'assistantChunk',
                    id: assistantId,
                    chunk: chunk
                });
            }

            const assistantMsg: ChatHistoryMessage = {
                id: assistantId,
                role: 'assistant',
                content: fullResponse,
                timestamp: Date.now()
            };
            this._messages.push(assistantMsg);

            this._postMessage({
                type: 'assistantDone',
                id: assistantId
            });

        } catch (err) {
            this._postMessage({
                type: 'assistantError',
                id: assistantId,
                error: 'Failed to get response from Abysius AI'
            });
        }
    }

    private _getEditorContext(): { language?: string; filename?: string; selectedText?: string; cursorLine?: number } {
        const editor = vscode.window.activeTextEditor;
        if (!editor) return {};

        const document = editor.document;
        const selection = editor.selection;
        
        return {
            language: document.languageId,
            filename: document.fileName,
            selectedText: selection.isEmpty ? undefined : document.getText(selection),
            cursorLine: selection.active.line + 1
        };
    }

    private _buildSystemPrompt(context: { language?: string; filename?: string; selectedText?: string; cursorLine?: number }): string {
        let prompt = `You are Abysius, an AI coding assistant embedded in a code editor. You help with programming, debugging, code review, and general software development questions.`;

        if (context.language) {
            prompt += `\n\nThe user is currently working in a ${context.language} file`;
            if (context.filename) {
                prompt += ` (${context.filename.split('/').pop()})`;
            }
            prompt += '.';
        }

        if (context.selectedText) {
            prompt += `\n\nSelected code:\n\`\`\`${context.language || ''}\n${context.selectedText}\n\`\`\``;
        }

        if (context.cursorLine) {
            prompt += `\n\nCursor is at line ${context.cursorLine}.`;
        }

        prompt += `\n\nWhen providing code, wrap it in markdown code blocks with the appropriate language tag. Be concise and helpful.`;
        
        return prompt;
    }

    private _insertCodeIntoEditor(code: string): void {
        const editor = vscode.window.activeTextEditor;
        if (!editor) {
            vscode.window.showWarningMessage('No active editor to insert code into');
            return;
        }

        editor.edit(editBuilder => {
            const selection = editor.selection;
            editBuilder.replace(selection, code);
        });
    }

    private _postMessage(message: any): void {
        if (this._view) {
            this._view.webview.postMessage(message);
        }
    }

    private _generateId(): string {
        return Date.now().toString(36) + Math.random().toString(36).substr(2);
    }

    private _getHtmlForWebview(webview: vscode.Webview): string {
        const styleUri = webview.asWebviewUri(
            vscode.Uri.joinPath(this._extensionUri, 'assets', 'chat.css')
        );
        const scriptUri = webview.asWebviewUri(
            vscode.Uri.joinPath(this._extensionUri, 'assets', 'chat.js')
        );

        const nonce = this._generateId();

        return `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src ${webview.cspSource} 'unsafe-inline'; script-src 'nonce-${nonce}'; connect-src https:;">
    <link href="${styleUri}" rel="stylesheet">
</head>
<body>
    <div id="chat-container">
        <div id="messages"></div>
        <div id="input-area">
            <textarea id="message-input" rows="1" placeholder="Ask Abysius..."></textarea>
            <button id="send-btn">Send</button>
            <button id="cancel-btn" style="display:none;">Stop</button>
        </div>
    </div>
    <script nonce="${nonce}" src="${scriptUri}"></script>
</body>
</html>`;
    }

    dispose(): void {
        this._currentStreamAbort?.abort();
    }
}
