const vscode = require('vscode');

class SecurityDiagnosticsProvider {
    constructor() {
        this.collection = vscode.languages.createDiagnosticCollection('vigthoria-security-devops');
        this.codeActionKinds = [vscode.CodeActionKind.QuickFix];
        this.rules = [
            {
                code: 'VSEC_HARDCODED_SECRET',
                severity: vscode.DiagnosticSeverity.Error,
                message: 'Hardcoded secret detected. Replace with env var.',
                regex: /(api[_-]?key|secret|token|password|jwt[_-]?secret)\s*[:=]\s*(["'`])([^"'`]{8,})\2/gi
            },
            {
                code: 'VSEC_WILDCARD_CORS',
                severity: vscode.DiagnosticSeverity.Warning,
                message: 'Wildcard CORS detected. Generate allowlist template.',
                regex: /(origin\s*[:=]\s*(["'])\*\2)|(access-control-allow-origin\s*[:=]\s*(["'])\*\4)/gi
            },
            {
                code: 'VSEC_JWT_FALLBACK',
                severity: vscode.DiagnosticSeverity.Error,
                message: 'JWT fallback secret detected. Remove fallback and add required check.',
                regex: /process\.env\.[A-Z0-9_]*JWT[A-Z0-9_]*\s*(\|\||\?\?)\s*(["'`]).+?\2/gi
            },
            {
                code: 'VSEC_BIND_ALL_INTERFACES',
                severity: vscode.DiagnosticSeverity.Warning,
                message: '0.0.0.0 binding detected. Change to 127.0.0.1.',
                regex: /(["'`])0\.0\.0\.0\1/g
            },
            {
                code: 'VSEC_INNERHTML_SINK',
                severity: vscode.DiagnosticSeverity.Warning,
                message: 'innerHTML sink detected. Use textContent or DOMPurify.',
                regex: /(\.innerHTML\s*=|dangerouslySetInnerHTML\s*=)/g
            }
        ];
    }

    register(context) {
        context.subscriptions.push(this.collection);

        const scanOpenEditors = () => {
            vscode.workspace.textDocuments.forEach(doc => this.updateDiagnostics(doc));
        };

        context.subscriptions.push(
            vscode.workspace.onDidOpenTextDocument(doc => this.updateDiagnostics(doc)),
            vscode.workspace.onDidChangeTextDocument(event => this.updateDiagnostics(event.document)),
            vscode.workspace.onDidCloseTextDocument(doc => this.collection.delete(doc.uri)),
            vscode.languages.registerCodeActionsProvider(
                { scheme: 'file' },
                this,
                { providedCodeActionKinds: this.codeActionKinds }
            )
        );

        scanOpenEditors();
    }

    updateDiagnostics(document) {
        if (!document || document.uri.scheme !== 'file') {
            return;
        }

        const diagnostics = [];
        const lines = document.getText().split(/\r?\n/);

        for (let lineNumber = 0; lineNumber < lines.length; lineNumber += 1) {
            const lineText = lines[lineNumber];

            for (const rule of this.rules) {
                rule.regex.lastIndex = 0;
                let match = rule.regex.exec(lineText);
                while (match) {
                    const startCol = match.index;
                    const endCol = startCol + match[0].length;
                    const range = new vscode.Range(lineNumber, startCol, lineNumber, endCol);
                    const diagnostic = new vscode.Diagnostic(range, rule.message, rule.severity);
                    diagnostic.source = 'Vigthoria Security DevOps';
                    diagnostic.code = rule.code;
                    diagnostics.push(diagnostic);
                    match = rule.regex.exec(lineText);
                }
            }
        }

        this.collection.set(document.uri, diagnostics);
    }

    provideCodeActions(document, _range, context) {
        const actions = [];
        for (const diagnostic of context.diagnostics) {
            if (!diagnostic.code) {
                continue;
            }

            const action = this.buildQuickFix(document, diagnostic);
            if (action) {
                actions.push(action);
            }
        }

        return actions;
    }

    buildQuickFix(document, diagnostic) {
        const code = String(diagnostic.code);
        const text = document.getText(diagnostic.range);

        if (code === 'VSEC_HARDCODED_SECRET') {
            return this.createSecretFix(document, diagnostic, text);
        }
        if (code === 'VSEC_WILDCARD_CORS') {
            return this.createCorsFix(document, diagnostic, text);
        }
        if (code === 'VSEC_JWT_FALLBACK') {
            return this.createJwtFallbackFix(document, diagnostic, text);
        }
        if (code === 'VSEC_BIND_ALL_INTERFACES') {
            return this.createHostFix(document, diagnostic, text);
        }
        if (code === 'VSEC_INNERHTML_SINK') {
            return this.createXssFix(document, diagnostic, text);
        }

        return null;
    }

    createSecretFix(document, diagnostic, text) {
        const keyMatch = text.match(/(api[_-]?key|secret|token|password|jwt[_-]?secret)/i);
        const envKey = (keyMatch ? keyMatch[1] : 'SECRET').replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase();
        const replacement = text.replace(/(["'`])[^"'`]{8,}\1/, `process.env.${envKey}`);
        return this.makeAction('Replace with env var', document, diagnostic, replacement);
    }

    createCorsFix(document, diagnostic, text) {
        let replacement = text.replace(/(["'])\*\1/g, "['https://app.example.com']");
        if (replacement === text) {
            replacement = "origin: ['https://app.example.com']";
        }
        return this.makeAction('Generate allowlist template', document, diagnostic, replacement);
    }

    createJwtFallbackFix(document, diagnostic, text) {
        const replacement = text.replace(/\s*(\|\||\?\?)\s*(["'`]).+?\2/, '');
        return this.makeAction('Remove fallback, add required check', document, diagnostic, replacement);
    }

    createHostFix(document, diagnostic, text) {
        const replacement = text.replace('0.0.0.0', '127.0.0.1');
        return this.makeAction('Change to 127.0.0.1', document, diagnostic, replacement);
    }

    createXssFix(document, diagnostic, text) {
        let replacement = text;
        if (text.includes('.innerHTML')) {
            replacement = text.replace('.innerHTML', '.textContent');
        }
        return this.makeAction('Use textContent or DOMPurify', document, diagnostic, replacement);
    }

    makeAction(title, document, diagnostic, replacement) {
        if (!replacement || replacement === document.getText(diagnostic.range)) {
            return null;
        }

        const action = new vscode.CodeAction(title, vscode.CodeActionKind.QuickFix);
        action.diagnostics = [diagnostic];
        action.isPreferred = true;

        const edit = new vscode.WorkspaceEdit();
        edit.replace(document.uri, diagnostic.range, replacement);
        action.edit = edit;
        return action;
    }
}

module.exports = {
    SecurityDiagnosticsProvider
};
