"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlindSpotEngine = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
/* eslint-disable no-control-regex */
const RULES = [
    {
        id: 'async-error-handling',
        category: 'error-handling',
        description: 'Async functions without try/catch or .catch()',
        severity: 'high',
        impact: 'This is your #1 bug source — 5x more crashes without error handling',
        suggestion: 'Wrap async function bodies in try/catch blocks',
        detectPattern: (code) => (code.match(/\basync\b.*(?:function|\w+\s*\()|\(\s*\)\s*=>/g) || []).length,
        detectMissing: (code) => {
            const hasAsync = /\basync\b/.test(code);
            const hasErrorHandling = /try\s*\{/.test(code) || /\.catch\s*\(/.test(code);
            return hasAsync && !hasErrorHandling;
        },
    },
    {
        id: 'null-param-check',
        category: 'null-safety',
        description: 'Function parameters used without null/undefined checks',
        severity: 'high',
        impact: 'Runtime crashes from "cannot read property of undefined"',
        suggestion: 'Add null checks or use optional chaining (?.)',
        detectPattern: (code) => (code.match(/function\s+\w+\s*\([^)]*\)|\w+\s*\([^)]*\)\s*{/g) || []).length,
        detectMissing: (code) => {
            const hasParams = /function\s+\w+\s*\([^)]+\)|const\s+\w+\s*=\s*\([^)]+\)/.test(code);
            const hasNullCheck = /if\s*\([^)]*null[^)]*\)|if\s*\([^)]*undefined[^)]*\)|\?\./.test(code);
            return hasParams && !hasNullCheck;
        },
    },
    {
        id: 'missing-return-type',
        category: 'type-safety',
        description: 'Functions missing return type annotations',
        severity: 'medium',
        impact: 'Type inference errors and reduced code clarity',
        suggestion: 'Add explicit return type annotations to functions',
        detectPattern: (code) => (code.match(/\bfunction\b\s+\w+|\bconst\b\s+\w+\s*=\s*(?:\basync\b\s*)?\(/g) || []).length,
        detectMissing: (code) => {
            const hasFunction = /\bfunction\b\s+\w+|\bconst\b\s+\w+\s*=\s*(?:\basync\b\s*)?\(/g.test(code);
            if (!hasFunction)
                return false;
            const typedFunctions = (code.match(/\bfunction\b\s+\w+[^)]*\)\s*:\s*\w+/g) || []).length;
            const allFunctions = (code.match(/\bfunction\b\s+\w+/g) || []).length;
            return typedFunctions < allFunctions * 0.3;
        },
    },
    {
        id: 'missing-input-validation',
        category: 'validation',
        description: 'User input/API params used without validation',
        severity: 'critical',
        impact: 'Security vulnerabilities and data integrity issues',
        suggestion: 'Validate all input using a validation library (zod, joi, etc.)',
        detectPattern: (code) => (code.match(/req\.(?:body|params|query)|\.get\(|\.post\(|params\.\w+/g) || []).length,
        detectMissing: (code) => {
            const hasInput = /req\.(?:body|params|query)|request\.(?:body|params)|params\.\w+/i.test(code);
            const hasValidation = /validate|\.parse\(|\.safeParse\(|schema\.|z\./i.test(code);
            return hasInput && !hasValidation;
        },
    },
    {
        id: 'missing-tests',
        category: 'testing',
        description: 'Functions exported but no corresponding tests found',
        severity: 'medium',
        impact: 'Untested code leads to more production bugs',
        suggestion: 'Add unit tests for exported functions',
        detectPattern: (code) => (code.match(/export\s+(?:const|function|class)\s+\w+/g) || []).length,
        detectMissing: (code, lang) => {
            const hasExports = /export\s+(?:const|function|class)\s+\w+/g.test(code);
            const hasTests = /describe\(|it\(|test\(/g.test(code);
            return hasExports && !hasTests;
        },
    },
    {
        id: 'missing-early-return',
        category: 'structure',
        description: 'Deeply nested conditionals without early returns',
        severity: 'low',
        impact: 'Complex code harder to read and maintain',
        suggestion: 'Use early returns/guard clauses instead of nested ifs',
        detectPattern: (code) => (code.match(/if\s*\(/g) || []).length,
        detectMissing: (code) => {
            const ifCount = (code.match(/if\s*\(/g) || []).length;
            const returnCount = (code.match(/return\b/g) || []).length;
            const lines = code.split('\n').length;
            if (lines < 20)
                return false;
            return ifCount > 3 && returnCount < ifCount;
        },
    },
    {
        id: 'promise-fire-forget',
        category: 'error-handling',
        description: 'Promise/async calls without await or error handling',
        severity: 'critical',
        impact: 'Silent failures — errors go unnoticed',
        suggestion: 'Always await async calls or attach .catch()',
        detectPattern: (code) => (code.match(/\w+\([^)]*\)/g) || []).length,
        detectMissing: (code) => {
            const hasAwait = /\bawait\b/g.test(code);
            const hasAsync = /\.then\(|\.catch\(|Promise\./g.test(code);
            return hasAsync && !hasAwait;
        },
    },
    {
        id: 'hardcoded-secrets',
        category: 'security',
        description: 'Hardcoded values that should be environment variables',
        severity: 'critical',
        impact: 'Security breach risk — secrets exposed in code',
        suggestion: 'Move secrets to .env file and use process.env',
        detectPattern: (code) => (code.match(/(?:const|let|var)\s+\w*\s*=\s*['"][^'"]{8,}['"]/g) || []).length,
        detectMissing: (code) => {
            const secretPatterns = /(?:api[_-]?key|secret|token|password|auth)\s*[:=]\s*['"][^'"]+/gi;
            const hasEnvCheck = /process\.env\.|import\.meta\.env\./g.test(code);
            return secretPatterns.test(code) && !hasEnvCheck;
        },
    },
    // ─── TESTING BLIND SPOTS ──────────────────────────────
    {
        id: 'complex-without-test',
        category: 'testing',
        description: 'Complex logic functions without corresponding tests',
        severity: 'high',
        impact: 'Untested complex functions are the #1 source of regression bugs',
        suggestion: 'Add unit tests covering edge cases and branches',
        detectPattern: (code) => (code.match(/if\s*\(|else\s*\{|switch\s*\(|for\s*\(|while\s*\(/g) || []).length,
        detectMissing: (code) => {
            const hasComplexLogic = (code.match(/if\s*\(|else\s*\{|switch\s*\(/g) || []).length > 3;
            const hasTests = /\bdescribe\b|\bit\s*\(|\btest\s*\(/g.test(code);
            return hasComplexLogic && !hasTests;
        },
    },
    {
        id: 'mock-heavy',
        category: 'testing',
        description: 'Tests with more mocks than assertions — fragile tests',
        severity: 'medium',
        impact: 'Mock-heavy tests break on refactors and give false confidence',
        suggestion: 'Reduce mocks, prefer integration tests for core logic',
        detectPattern: (code) => (code.match(/\bjest\.(?:fn|mock|spy)/g) || []).length,
        detectMissing: (code) => {
            if (!/\bjest\.(?:fn|mock|spy)/g.test(code))
                return false;
            const mocks = (code.match(/\bjest\.(?:fn|mock|spy)/g) || []).length;
            const assertions = (code.match(/\b(?:expect|assert|should)\./g) || []).length;
            return mocks > assertions && mocks > 2;
        },
    },
    // ─── PERFORMANCE BLIND SPOTS ──────────────────────────
    {
        id: 'large-bundle-import',
        category: 'performance',
        description: 'Importing entire libraries instead of specific exports',
        severity: 'medium',
        impact: 'Large bundle size increases load time and memory usage',
        suggestion: 'Import only specific exports: import { X } from "lib" instead of import *',
        detectPattern: (code) => (code.match(/\bimport\s+\*\s+as\s+\w+/g) || []).length,
        detectMissing: (code) => /\bimport\s+\*\s+as\b/g.test(code),
    },
    {
        id: 'missing-memo',
        category: 'performance',
        description: 'Callback/object props created inline without memoization',
        severity: 'low',
        impact: 'Unnecessary re-renders in React components',
        suggestion: 'Wrap callbacks in useCallback and objects in useMemo',
        detectPattern: (code) => (code.match(/\bon\w+\s*=\s*\{?\s*\(/g) || []).length,
        detectMissing: (code) => {
            const hasInlineCallbacks = /on\w+\s*=\s*\{?\s*\(/g.test(code);
            const hasMemo = /\buseCallback\b|\buseMemo\b/g.test(code);
            return hasInlineCallbacks && !hasMemo;
        },
    },
    {
        id: 'n-plus-one',
        category: 'performance',
        description: 'Potential N+1 query pattern — queries inside loops',
        severity: 'high',
        impact: 'N+1 queries cause severe performance degradation at scale',
        suggestion: 'Use batch queries or eager loading instead of loop queries',
        detectPattern: (code) => (code.match(/\bfor\b|\bwhile\b|\bforEach\b/g) || []).length,
        detectMissing: (code) => {
            const hasLoop = /\bfor\b|\bwhile\b|\bforEach\b|\bmap\b/g.test(code);
            const hasQuery = /\.(?:find|query|findMany|findUnique|get)\s*\(/g.test(code);
            return hasLoop && hasQuery;
        },
    },
    {
        id: 'missing-loading-state',
        category: 'performance',
        description: 'Async data fetch without loading state handling',
        severity: 'medium',
        impact: 'Users see blank screens or flash of incorrect UI',
        suggestion: 'Always handle loading and error states for async operations',
        detectPattern: (code) => (code.match(/\bawait\b|\.then\s*\(|\.query\s*\(/g) || []).length,
        detectMissing: (code) => {
            const hasAsync = /\bawait\b|\.then\s*\(/g.test(code);
            const hasLoading = /\bisLoading\b|\bisFetching\b|\bstatus\s*===?\s*['"]loading['"]|\bloading\b/g.test(code);
            return hasAsync && !hasLoading && /\buseQuery\b|\buseMutation\b|fetch\s*\(/g.test(code);
        },
    },
    // ─── SECURITY BLIND SPOTS ─────────────────────────────
    {
        id: 'sql-injection',
        category: 'security',
        description: 'Raw SQL queries using string interpolation — SQL injection risk',
        severity: 'critical',
        impact: 'SQL injection can lead to data breach and database takeover',
        suggestion: 'Use parameterized queries or ORM with safe query builders',
        detectPattern: (code) => (code.match(/`[^`]*\$\{[^`]*query[^`]*`|['"]["']\s*\+\s*['"]["']/gi) || []).length,
        detectMissing: (code) => {
            const rawQuery = /\$\{.*\}\s*['"]|['"]\s*\+\s*['"][^'"]*SELECT|INSERT|UPDATE|DELETE/i.test(code);
            const hasParams = /\$1|:param\b|\?/g.test(code) || /\.(?:prepare|execute)\s*\(/g.test(code);
            return rawQuery && !hasParams;
        },
    },
    {
        id: 'sensitive-logs',
        category: 'security',
        description: 'Logging sensitive data (tokens, passwords, secrets)',
        severity: 'high',
        impact: 'Sensitive data in logs can leak in production monitoring',
        suggestion: 'Redact sensitive fields before logging: const { password, ...safe } = data',
        detectPattern: (code) => (code.match(/\bconsole\.(?:log|error|warn|debug)\s*\(/g) || []).length,
        detectMissing: (code) => {
            const logs = code.match(/\bconsole\.(?:log|error|warn|debug)\s*\([^)]{0,200}\)/gi);
            if (!logs)
                return false;
            return logs.some(l => /token|secret|password|key|auth|session|jwt/i.test(l));
        },
    },
    {
        id: 'missing-auth-check',
        category: 'security',
        description: 'API endpoints without authorization checks',
        severity: 'critical',
        impact: 'Unauthorized access to protected resources',
        suggestion: 'Add authentication/authorization middleware to protected routes',
        detectPattern: (code) => (code.match(/\.(?:get|post|put|delete|patch)\s*\(/g) || []).length,
        detectMissing: (code) => {
            const hasEndpoints = /\.(?:get|post|put|delete|patch)\s*\(/g.test(code);
            const hasAuth = /\b(?:auth|authenticate|authorize|protect|requireAuth)\b/i.test(code);
            return hasEndpoints && !hasAuth;
        },
    },
    // ─── NEW MICRO-FEATURE RULES ──────────────────────────
    {
        id: 'error-boundaries',
        category: 'error-handling',
        description: 'React components without error boundaries',
        severity: 'medium',
        impact: 'Unhandled React errors crash entire component tree',
        suggestion: 'Wrap components in ErrorBoundary or use error boundaries',
        detectPattern: (code) => (code.match(/return\s*<[^>]*>|React\.createElement/g) || []).length,
        detectMissing: (code) => {
            const hasComponents = /return\s*<[A-Z]|export\s+default\s+function\s+[A-Z]/.test(code);
            const hasBoundary = /ErrorBoundary|errorBoundary|componentDidCatch|getDerivedStateFromError/i.test(code);
            return hasComponents && !hasBoundary;
        },
    },
    {
        id: 'error-propagation',
        category: 'error-handling',
        description: 'Caught errors being swallowed (empty catch blocks or silent ignore)',
        severity: 'high',
        impact: 'Silent errors make debugging impossible — root cause hidden',
        suggestion: 'Always log or rethrow errors. Never leave catch blocks empty.',
        detectPattern: (code) => (code.match(/\bcatch\s*\([^)]*\)\s*\{/g) || []).length,
        detectMissing: (code) => {
            const catches = code.match(/\bcatch\s*\([^)]*\)\s*\{[\s\S]{0,50}\}/g);
            if (!catches)
                return false;
            return catches.some(c => !/\b(?:console|log|error|throw|rethrow|next|handle|notify)/i.test(c));
        },
    },
    {
        id: 'test-naming-quality',
        category: 'testing',
        description: 'Tests with generic/uninformative names (should work, test1, etc.)',
        severity: 'low',
        impact: 'Unclear test names make debugging failures harder than needed',
        suggestion: 'Use descriptive test names: "returns user when valid email provided"',
        detectPattern: (code) => (code.match(/\b(?:it|test)\s*\(['"][^'"]*['"]/g) || []).length,
        detectMissing: (code) => {
            const tests = code.match(/\b(?:it|test)\s*\(['"][^'"]*['"]/g);
            if (!tests)
                return false;
            return tests.some(t => {
                const name = t.match(/['"]([^'"]*)['"]/);
                return name && /^(should|test\d*|works?|passes?|fails?|x|test_func|test_\d+)$/i.test(name[1]);
            });
        },
    },
    {
        id: 'missing-pagination',
        category: 'performance',
        description: 'Data queries without pagination — potential memory issue',
        severity: 'medium',
        impact: 'Unpaginated queries crash on large datasets, memory exhaustion',
        suggestion: 'Add limit/offset or cursor-based pagination to all list endpoints',
        detectPattern: (code) => (code.match(/\.(?:findMany|find|query|select|get)\s*\(/g) || []).length,
        detectMissing: (code) => {
            const hasQuery = /\.(?:findMany|find|query|get|all)\s*\(/g.test(code);
            const hasPagination = /\b(?:limit|offset|cursor|skip|take|pagination|page|perPage)\b/i.test(code);
            return hasQuery && !hasPagination && /\b(?:list|all|findMany|getAll|index|search)\b/i.test(code);
        },
    },
    {
        id: 'unoptimized-images',
        category: 'performance',
        description: 'Images loaded without optimization (no width/height, lazy loading)',
        severity: 'low',
        impact: 'Unoptimized images cause layout shifts and slow page loads',
        suggestion: 'Add width/height attributes, lazy loading, and use optimized formats',
        detectPattern: (code) => (code.match(/<img[^>]*>/g) || []).length,
        detectMissing: (code) => {
            const imgs = code.match(/<img[^>]*>/g);
            if (!imgs)
                return false;
            return imgs.some(img => !/\b(?:loading\s*=\s*['"]lazy|width\s*=|srcSet|sizes\s*=)/i.test(img));
        },
    },
    {
        id: 'async-test-mistakes',
        category: 'testing',
        description: 'Async tests without proper await or done callback',
        severity: 'high',
        impact: 'Async test mistakes cause false positives — tests pass when they should fail',
        suggestion: 'Always await async operations in tests, use done() for callbacks',
        detectPattern: (code) => (code.match(/\b(?:it|test)\s*\(['"][^'"]*['"]\s*,\s*(?:async\s*)?\(/g) || []).length,
        detectMissing: (code) => {
            const asyncTests = code.match(/\b(?:it|test)\s*\(['"][^'"]*['"]\s*,\s*async\s*\(/g);
            if (!asyncTests)
                return false;
            const hasAwait = /\bawait\b/g.test(code);
            return asyncTests.length > 0 && !hasAwait;
        },
    },
    // ─── FINAL 8 MICRO-FEATURE RULES ──────────────────────
    {
        id: 'edge-cases-skip',
        category: 'error-handling',
        description: 'Skipping edge case handling (empty arrays, null, undefined)',
        severity: 'high',
        impact: 'Edge cases skipped cause runtime crashes in production',
        suggestion: 'Add null/undefined checks, handle empty arrays, validate inputs',
        detectPattern: (code) => (code.match(/\bmap\b|\bforEach\b|\bfilter\b|\.\w+\s*\(/g) || []).length,
        detectMissing: (code) => {
            const hasArrayOps = /\b(?:map|forEach|filter|reduce)\s*\(/.test(code);
            const hasEdgeChecks = /\.(?:length|size)\s*[>=]|!=\s*(?:null|undefined)|\.\?\.|if\s*\([^)]*null/i.test(code);
            return hasArrayOps && !hasEdgeChecks;
        },
    },
    {
        id: 'generic-error-messages',
        category: 'error-handling',
        description: 'Using generic error messages instead of specific, actionable ones',
        severity: 'low',
        impact: 'Generic errors make debugging harder — "Something went wrong" helps no one',
        suggestion: 'Add specific error details: what failed, why, and how to fix',
        detectPattern: (code) => (code.match(/['"][^'"]{10,100}['"]/g) || []).length,
        detectMissing: (code) => {
            const errors = code.match(/['"][^'"]*(?:error|fail|invalid|wrong|bad|issue|problem)[^'"]*['"]/gi);
            if (!errors)
                return false;
            return errors.some(e => /(?:something|an error|failed|error occurred|bad request|invalid)/i.test(e) && e.length < 40);
        },
    },
    {
        id: 'logging-pattern',
        category: 'error-handling',
        description: 'Inconsistent logging — sometimes logged, sometimes silently ignored',
        severity: 'medium',
        impact: 'Inconsistent logging makes debugging unreliable — you never know where to look',
        suggestion: 'Establish a consistent logging strategy: always log catch blocks, avoid console.log in prod',
        detectPattern: (code) => (code.match(/\bcatch\s*\(/g) || []).length,
        detectMissing: (code) => {
            const catches = (code.match(/\bcatch\s*\(/g) || []).length;
            const logs = (code.match(/\bconsole\.(?:log|error|warn|debug)/g) || []).length;
            const logger = /\blogger\b|\blog\.\w+|\bwinston\b|\bpino\b/i.test(code);
            if (catches === 0)
                return false;
            return catches > logs && !logger;
        },
    },
    {
        id: 'edge-case-tests-missing',
        category: 'testing',
        description: 'Tests only cover happy path — no edge case tests',
        severity: 'high',
        impact: 'Edge cases untested = production bugs waiting to happen',
        suggestion: 'Add tests for: empty states, error states, boundary values, null inputs',
        detectPattern: (code) => (code.match(/\b(?:expect|assert|should)\./g) || []).length,
        detectMissing: (code) => {
            const assertions = (code.match(/\b(?:expect|assert|should)\./g) || []).length;
            const edgeTests = /null|undefined|empty|error|reject|fail|throw|boundary|invalid|missing/i.test(code);
            return assertions > 2 && !edgeTests;
        },
    },
    {
        id: 'happy-path-only',
        category: 'testing',
        description: 'Tests only check success scenarios, no failure/error scenarios',
        severity: 'high',
        impact: 'Without failure tests, error handling code is never validated',
        suggestion: 'Add test cases for: API failures, auth failures, validation errors, network timeouts',
        detectPattern: (code) => (code.match(/\bit\s*\(['"][^'"]*['"]/g) || []).length,
        detectMissing: (code) => {
            const tests = (code.match(/\bit\s*\(['"][^'"]*['"]/g) || []).length;
            if (tests < 2)
                return false;
            const failureTests = /(?:fail|error|reject|timeout|unauthorized|forbidden|not\s+found|bad\s+request)/i.test(code);
            return !failureTests;
        },
    },
    {
        id: 'integration-vs-unit',
        category: 'testing',
        description: 'Too few integration tests compared to unit tests — missing real-world scenarios',
        severity: 'medium',
        impact: 'Unit-only testing misses integration bugs that happen in production',
        suggestion: 'Maintain a balanced ratio: 70% unit, 20% integration, 10% e2e',
        detectPattern: (code) => (code.match(/\bjest\.(?:fn|mock)/g) || []).length,
        detectMissing: (code) => {
            const mocks = (code.match(/\bjest\.(?:fn|mock)/g) || []).length;
            const integrationTests = /(?:request|supertest|render|mount|visit|browser|page\.)/i.test(code);
            return mocks > 5 && !integrationTests;
        },
    },
    {
        id: 'missing-db-indexes',
        category: 'performance',
        description: 'Database queries on fields without indexes — slow at scale',
        severity: 'medium',
        impact: 'Missing indexes cause query slowdown as data grows, leading to timeouts',
        suggestion: 'Add indexes on frequently queried fields (foreign keys, status, dates)',
        detectPattern: (code) => (code.match(/\.(?:findMany|findUnique|where|orderBy|filter)/g) || []).length,
        detectMissing: (code) => {
            const hasQueries = /\.(?:findMany|findUnique|where)\s*\(/g.test(code);
            const hasIndexes = /\b(?:index|unique|@@index|@Index|indexed)\b/i.test(code);
            const hasSchema = /(?:schema|model|prisma|typeorm|entity|table)/i.test(code);
            return hasQueries && hasSchema && !hasIndexes;
        },
    },
    {
        id: 'missing-rate-limit',
        category: 'security',
        description: 'API endpoints without rate limiting — DoS vulnerability',
        severity: 'critical',
        impact: 'Without rate limiting, API can be overwhelmed by excessive requests',
        suggestion: 'Add rate limiting middleware (express-rate-limit, @nestjs/throttler, etc.)',
        detectPattern: (code) => (code.match(/\.(?:get|post|put|delete|patch)\s*\(/g) || []).length,
        detectMissing: (code) => {
            const hasEndpoints = /\.(?:get|post|put|delete|patch)\s*\(/g.test(code);
            const hasRateLimit = /\b(?:rate.?limit|throttle|express-rate-limit|@nestjs\/throttler|limiter)\b/i.test(code);
            return hasEndpoints && !hasRateLimit && /\b(?:app|router|server)\b/i.test(code);
        },
    },
];
class BlindSpotEngine {
    store = [];
    storePath;
    constructor(cellDir) {
        this.storePath = path.join(cellDir, 'blind-spots.json');
        this.load();
    }
    analyze(code, lang) {
        const found = [];
        for (const rule of RULES) {
            if (rule.detectMissing(code, lang)) {
                const existing = this.store.find(s => s.id === rule.id);
                const hitRate = existing ? (existing.hitRate * existing.missedRate + 1) / (existing.missedRate + 2) : 0.5;
                const missedRate = existing ? existing.missedRate + 1 : 1;
                const bs = {
                    id: rule.id,
                    category: rule.category,
                    description: rule.description,
                    severity: rule.severity,
                    hitRate: Math.round(hitRate * 100) / 100,
                    missedRate,
                    impact: rule.impact,
                    suggestion: rule.suggestion,
                    examples: existing?.examples || [],
                };
                found.push(bs);
                const idx = this.store.findIndex(s => s.id === rule.id);
                if (idx >= 0) {
                    this.store[idx] = bs;
                }
                else {
                    this.store.push(bs);
                }
            }
        }
        this.save();
        return found;
    }
    getTop(count = 3) {
        return this.store
            .filter(s => s.missedRate >= 1)
            .sort((a, b) => b.missedRate - a.missedRate)
            .slice(0, count);
    }
    getSummary() {
        return {
            total: this.store.length,
            critical: this.store.filter(s => s.severity === 'critical').length,
            high: this.store.filter(s => s.severity === 'high').length,
            top: this.getTop(5),
        };
    }
    getAll() {
        return [...this.store].sort((a, b) => b.missedRate - a.missedRate);
    }
    reset() {
        this.store = [];
        this.save();
    }
    save() {
        try {
            const dir = path.dirname(this.storePath);
            if (!fs.existsSync(dir))
                fs.mkdirSync(dir, { recursive: true });
            fs.writeFileSync(this.storePath, JSON.stringify(this.store, null, 2));
        }
        catch { }
    }
    load() {
        try {
            if (fs.existsSync(this.storePath)) {
                this.store = JSON.parse(fs.readFileSync(this.storePath, 'utf-8'));
            }
        }
        catch { }
    }
}
exports.BlindSpotEngine = BlindSpotEngine;
//# sourceMappingURL=blind-spot-engine.js.map