/**
 * Validation scheduler for Acurity Architect diagnostics.
 * Manages timing, debouncing, and validation triggering.
 */

import * as vscode from "vscode";
import { LANGUAGE_ID } from "../../../core/src/constants.js";

const DEFAULT_VALIDATION_DEBOUNCE_MS = 150;
const validationTimers = new Map();

/**
 * Checks if a document is an Acurity document.
 * @param {vscode.TextDocument} document - The document to check
 * @returns {boolean} - True if Acurity document
 */
function isAcurityDocument(document) {
    return document && document.languageId === LANGUAGE_ID;
}

/**
 * Gets the configured validation debounce delay.
 * @returns {number} - Debounce delay in milliseconds
 */
function getValidationDebounceMs() {
    const configured = vscode.workspace.getConfiguration("acurity").get("diagnostics.debounceMs", DEFAULT_VALIDATION_DEBOUNCE_MS);
    const normalized = Number(configured);
    if (!Number.isFinite(normalized)) {
        return DEFAULT_VALIDATION_DEBOUNCE_MS;
    }

    return Math.max(0, Math.floor(normalized));
}

/**
 * Determines if content changes represent a small edit that should trigger immediate validation.
 * Small edits typically come from quick fixes and should provide instant visual feedback.
 * @param {vscode.TextDocumentContentChangeEvent[]} contentChanges - The content changes
 * @returns {boolean} - True if this appears to be a small edit
 */
function isSmallEdit(contentChanges) {
    if (!contentChanges || contentChanges.length === 0) {
        return false;
    }

    // Consider it a small edit if:
    // 1. Single change event (not multiple simultaneous edits)
    // 2. Affects only one line (range.isSingleLine)
    // 3. Changes less than 20 characters
    if (contentChanges.length === 1) {
        const change = contentChanges[0];
        const isSingleLine = change.range.isSingleLine;
        const textLength = change.text.length;
        const rangeLength = change.rangeLength || 0;
        
        // Quick fixes typically replace a small token (e.g., "function" -> "FUNCTION")
        // Allow up to 20 characters changed
        return isSingleLine && Math.max(textLength, rangeLength) <= 20;
    }

    return false;
}

/**
 * Clears any pending validation timer for a document.
 * @param {vscode.Uri} uri - The document URI
 */
function clearPendingValidation(uri) {
    const key = uri.toString();
    const pending = validationTimers.get(key);
    if (pending) {
        clearTimeout(pending);
        validationTimers.delete(key);
    }
}

/**
 * Schedules validation for a document with appropriate timing.
 * @param {vscode.TextDocument} document - The document to validate
 * @param {Function} validationCallback - Callback to invoke when validation should run
 * @param {boolean} immediate - Force immediate validation (skip debounce)
 */
function scheduleValidation(document, validationCallback, immediate = false) {
    if (!isAcurityDocument(document)) {
        return;
    }

    const uriKey = document.uri.toString();
    clearPendingValidation(document.uri);

    // For small edits (like quick fixes), validate immediately to provide instant feedback
    // For larger edits, use debounce to avoid excessive validation during typing
    const debounceMs = immediate ? 0 : getValidationDebounceMs();
    const timer = setTimeout(async () => {
        validationTimers.delete(uriKey);

        const latestDocument = vscode.workspace.textDocuments.find((doc) => doc.uri.toString() === uriKey) || document;
        await validationCallback(latestDocument);
    }, debounceMs);

    validationTimers.set(uriKey, timer);
}

/**
 * Clears all pending validation timers.
 */
function clearAllPendingValidations() {
    validationTimers.forEach((timer) => clearTimeout(timer));
    validationTimers.clear();
}

export {
    isAcurityDocument,
    isSmallEdit,
    scheduleValidation,
    clearPendingValidation,
    clearAllPendingValidations
};
