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

export class InlineCompletionProvider implements vscode.InlineCompletionItemProvider {
    private api: AbysiusApi;
    private debounceTimer: NodeJS.Timeout | undefined;
    private currentAbortController: AbortController | undefined;
    private visibleCompletion: vscode.InlineCompletionItem | undefined;
    private editor: vscode.TextEditor | undefined;
    
    // Track accept/reject for analytics
    private pendingCompletion: { text: string; accepted: boolean } | undefined;

    constructor(api: AbysiusApi) {
        this.api = api;
    }

    async provideInlineCompletionItems(
        document: vscode.TextDocument,
        position: vscode.Position,
        context: vscode.InlineCompletionContext,
        token: vscode.CancellationToken
    ): Promise<vscode.InlineCompletionItem[] | vscode.InlineCompletionList | undefined> {
        
        const config = vscode.workspace.getConfiguration('abysius');
        if (!config.get<boolean>('enableInlineCompletions', true)) {
            return undefined;
        }

        // Don't trigger on comments or strings (basic heuristic)
        const lineText = document.lineAt(position.line).text;
        if (this._isInComment(lineText, position.character)) {
            return undefined;
        }

        // Get prefix and suffix around cursor
        const prefix = document.getText(new vscode.Range(new vscode.Position(0, 0), position));
        const suffix = document.getText(new vscode.Range(position, document.positionAt(document.getText().length)));

        // Minimum context length heuristic
        const lastLinePrefix = lineText.substring(0, position.character).trim();
        if (lastLinePrefix.length < 2 && prefix.split('\n').length < 3) {
            return undefined;
        }

        const request: InlineRequest = {
            prompt: prefix,
            suffix: suffix,
            language: document.languageId,
            filename: document.fileName
        };

        const delay = config.get<number>('inlineCompletionDelay', 300);
        
        return new Promise((resolve) => {
            if (this.debounceTimer) {
                clearTimeout(this.debounceTimer);
            }

            this.debounceTimer = setTimeout(async () => {
                this.currentAbortController = new AbortController();
                
                const disposable = token.onCancellationRequested(() => {
                    this.currentAbortController?.abort();
                });

                try {
                    const response = await this.api.getInlineCompletion(
                        request,
                        this.currentAbortController.signal
                    );

                    disposable.dispose();

                    if (!response || !response.completion) {
                        resolve(undefined);
                        return;
                    }

                    const completionText = response.completion;
                    
                    // Build inline completion item
                    const item = new vscode.InlineCompletionItem(
                        completionText,
                        new vscode.Range(position, position)
                    );
                    
                    item.command = {
                        command: 'abysius._onCompletionShown',
                        title: 'Completion Shown',
                        arguments: [completionText]
                    };

                    this.visibleCompletion = item;
                    this.pendingCompletion = { text: completionText, accepted: false };
                    this.editor = vscode.window.activeTextEditor;

                    vscode.commands.executeCommand('setContext', 'abysiusInlineCompletionVisible', true);

                    resolve([item]);
                } catch (err) {
                    disposable.dispose();
                    resolve(undefined);
                }
            }, delay);

            token.onCancellationRequested(() => {
                clearTimeout(this.debounceTimer);
                this.currentAbortController?.abort();
                resolve(undefined);
            });
        });
    }

    handleDidShowCompletionItem(completionItem: vscode.InlineCompletionItem): void {
        // Called when VS Code shows our completion
    }

    handleDidPartiallyAcceptCompletionItem(
        completionItem: vscode.InlineCompletionItem,
        acceptedLength: number
    ): void {
        if (this.pendingCompletion) {
            this.pendingCompletion.accepted = true;
        }
    }

    accept(): void {
        if (this.pendingCompletion) {
            this.pendingCompletion.accepted = true;
        }
        this._hide();
    }

    reject(): void {
        this._hide();
    }

    trigger(): void {
        // Trigger completion manually
        vscode.commands.executeCommand('editor.action.inlineSuggest.trigger');
    }

    acceptNextWord(): void {
        if (!this.visibleCompletion || !this.editor) return;

        const completion = this.visibleCompletion.insertText as string;
        const nextSpace = completion.search(/\s/);
        const wordLength = nextSpace === -1 ? completion.length : nextSpace + 1;
        
        const position = this.editor.selection.active;
        const range = new vscode.Range(position, position.translate(0, wordLength));
        
        this.editor.edit(editBuilder => {
            editBuilder.replace(range, completion.substring(0, wordLength));
        });
    }

    private _hide(): void {
        this.visibleCompletion = undefined;
        this.editor = undefined;
        vscode.commands.executeCommand('setContext', 'abysiusInlineCompletionVisible', false);
        vscode.commands.executeCommand('editor.action.inlineSuggest.hide');
    }

    private _isInComment(lineText: string, charIndex: number): boolean {
        const beforeCursor = lineText.substring(0, charIndex);
        
        // Simple heuristics for common comment styles
        if (beforeCursor.trimStart().startsWith('//')) return true;
        if (beforeCursor.trimStart().startsWith('#')) return true;
        if (beforeCursor.trimStart().startsWith('--')) return true;
        if (beforeCursor.trimStart().startsWith('*')) {
            const trimmed = beforeCursor.trim();
            if (trimmed.startsWith('*') && !trimmed.startsWith('**')) return true;
        }
        
        return false;
    }

    dispose(): void {
        if (this.debounceTimer) {
            clearTimeout(this.debounceTimer);
        }
        this.currentAbortController?.abort();
    }
}
