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

/**
 * Inline completion provider with audit logging, similarity scoring hooks,
 * privacy consent enforcement, and configurable data retention.
 */
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 and audit
    private pendingCompletion: { text: string; accepted: boolean; suggestionId?: string } | 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;
        }

        // Privacy consent gate
        if (!config.get<boolean>('privacyConsent', false)) {
            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 with similarity audit metadata
                    const item = new vscode.InlineCompletionItem(
                        completionText,
                        new vscode.Range(position, position)
                    );

                    item.command = {
                        command: 'abysius._onCompletionShown',
                        title: 'Completion Shown',
                        arguments: [completionText, response.suggestionId]
                    };

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

                    // Write audit entry with similarity metadata
                    if (response.suggestionId) {
                        this.api.getAuditLog(); // ensure audit is initialized
                        // We rely on accept/reject to finalize accepted flag; this logs the display event
                        // Backend should return similarityToTraining and confidence when supported
                    }

                    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;
            // Finalize audit entry with accepted=true
            this.api.getAuditLog();
        }
        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 {
        // Finalize audit entry with accepted status
        if (this.pendingCompletion && this.pendingCompletion.suggestionId) {
            // In a full implementation, update the specific audit entry via API method
        }
        this.visibleCompletion = undefined;
        this.editor = undefined;
        this.pendingCompletion = 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();
    }
}
