/**
 * Verification Checklist Module
 * 
 * Provides a structured checklist system for mission completion verification.
 * 
 * The LLM creates and checks items in .opencode/verification-checklist.md
 * The hook system verifies all items are checked before allowing CONCLUDE.
 */

import { existsSync, readFileSync } from "node:fs";
import { join } from "node:path";
import {
    PATHS,
    MISSION_CONTROL,
    // Verification constants
    CHECKLIST,
    CHECKLIST_PATTERNS,
    CHECKLIST_CATEGORIES,
    type ChecklistCategory,
    type ChecklistItem,
    type ChecklistVerificationResult,
    type VerificationResult,
} from "../../shared/index.js";
import { log } from "../agents/logger.js";

export const CHECKLIST_FILE = CHECKLIST.FILE;



// ============================================================================
// Parsing Functions
// ============================================================================


function parseChecklistLine(line: string, currentCategory: ChecklistCategory): ChecklistItem | null {
    const trimmedLine = line.trim();

    // Try parsing with ID format: - [ ] **ID**: Description
    const idMatch = trimmedLine.match(CHECKLIST_PATTERNS.ITEM_WITH_ID);
    if (idMatch) {
        return {
            id: idMatch[2].toLowerCase().replace(/\s+/g, '-'),
            category: currentCategory,
            description: idMatch[3],
            completed: idMatch[1].toLowerCase() === 'x',
        };
    }

    // Try parsing simple format: - [ ] Description
    const simpleMatch = trimmedLine.match(CHECKLIST_PATTERNS.SIMPLE_ITEM);
    if (simpleMatch) {
        const desc = simpleMatch[2];
        return {
            id: desc.toLowerCase().replace(/\s+/g, '-').substring(0, 30),
            category: currentCategory,
            description: desc,
            completed: simpleMatch[1].toLowerCase() === 'x',
        };
    }

    return null;
}


function detectCategory(headerLine: string): ChecklistCategory {
    const headerLower = headerLine.toLowerCase();

    if (headerLower.includes('code quality') || headerLower.includes('lint') || headerLower.includes('type')) {
        return CHECKLIST_CATEGORIES.IDS.CODE_QUALITY;
    }
    if (headerLower.includes('unit test')) {
        return CHECKLIST_CATEGORIES.IDS.UNIT_TESTS;
    }
    if (headerLower.includes('integration') || headerLower.includes('e2e')) {
        return CHECKLIST_CATEGORIES.IDS.INTEGRATION_TESTS;
    }
    if (headerLower.includes('build')) {
        return CHECKLIST_CATEGORIES.IDS.BUILD;
    }
    if (headerLower.includes('runtime') || headerLower.includes('start') || headerLower.includes('run')) {
        return CHECKLIST_CATEGORIES.IDS.RUNTIME;
    }
    if (headerLower.includes('infrastructure') || headerLower.includes('environment') ||
        headerLower.includes('docker') || headerLower.includes('deploy')) {
        return CHECKLIST_CATEGORIES.IDS.INFRASTRUCTURE;
    }

    return CHECKLIST_CATEGORIES.IDS.CUSTOM;
}


export function parseChecklist(content: string): ChecklistItem[] {
    const items: ChecklistItem[] = [];
    const lines = content.split('\n');

    let currentCategory: ChecklistCategory = CHECKLIST_CATEGORIES.IDS.CUSTOM;

    for (const line of lines) {
        const trimmed = line.trim();

        // Check for category header
        if (trimmed.startsWith('## ')) {
            currentCategory = detectCategory(trimmed);
            continue;
        }

        // Try to parse as checklist item
        const item = parseChecklistLine(line, currentCategory);
        if (item) {
            items.push(item);
        }
    }

    return items;
}


export function readChecklist(directory: string): ChecklistItem[] {
    const filePath = join(directory, CHECKLIST_FILE);

    if (!existsSync(filePath)) {
        return [];
    }

    try {
        const content = readFileSync(filePath, 'utf-8');
        return parseChecklist(content);
    } catch (error) {
        log(`[checklist] Failed to read checklist: ${error}`);
        return [];
    }
}

// ============================================================================
// Verification Functions
// ============================================================================


export function verifyChecklist(directory: string): ChecklistVerificationResult {
    const result: ChecklistVerificationResult = {
        passed: false,
        totalItems: 0,
        completedItems: 0,
        incompleteItems: 0,
        progress: "0/0",
        incompleteList: [],
        errors: []
    };

    const filePath = join(directory, CHECKLIST_FILE);

    // Check if checklist file exists
    if (!existsSync(filePath)) {
        result.errors.push(`Verification checklist not found at ${CHECKLIST_FILE}`);
        result.errors.push("Create checklist with at least: build, tests, and any environment-specific checks");
        return result;
    }

    // Parse checklist
    const items = readChecklist(directory);

    if (items.length === 0) {
        result.errors.push("Verification checklist is empty");
        result.errors.push("Add verification items (build, tests, environment checks)");
        return result;
    }

    // Count completions
    result.totalItems = items.length;
    result.completedItems = items.filter(i => i.completed).length;
    result.incompleteItems = result.totalItems - result.completedItems;
    result.progress = `${result.completedItems}/${result.totalItems}`;

    // Collect incomplete items
    result.incompleteList = items
        .filter(i => !i.completed)
        .map(i => `[${CHECKLIST_CATEGORIES.LABELS[i.category]}] ${i.description}`);

    if (result.incompleteItems > 0) {
        result.errors.push(`Checklist incomplete: ${result.progress}`);
    }

    result.passed = result.incompleteItems === 0 && result.totalItems > 0;

    log("[checklist] Verification result", {
        passed: result.passed,
        progress: result.progress,
        totalItems: result.totalItems,
        completedItems: result.completedItems
    });

    return result;
}




const TODO_INCOMPLETE_PATTERN = /^[-*]\s*\[\s*\]/gm;

const TODO_COMPLETE_PATTERN = /^[-*]\s*\[[xX]\]/gm;

const SYNC_ISSUE_PATTERNS = [
    /^[-*]\s+\S/gm,
    /ERROR/gi,
    /FAIL/gi,
    /CONFLICT/gi,
];


function countMatches(text: string, pattern: RegExp): number {
    const matches = text.match(pattern);
    return matches?.length ?? 0;
}


function hasRealSyncIssues(content: string): boolean {
    const trimmed = content.trim();
    if (!trimmed) return false;
    if (/^#\s*Sync Issues\s*$/i.test(trimmed)) return false;

    for (const pattern of SYNC_ISSUE_PATTERNS) {
        if (pattern.test(trimmed)) return true;
    }

    const lines = trimmed.split('\n').filter(l => {
        const line = l.trim();
        return line && !line.startsWith('#') && line !== '---';
    });

    return lines.length > 0;
}


export function verifyMissionCompletion(directory: string): VerificationResult {
    const result: VerificationResult = {
        passed: false,
        todoComplete: false,
        todoProgress: "0/0",
        todoIncomplete: 0,
        syncIssuesEmpty: true,
        syncIssuesCount: 0,
        checklistComplete: false,
        checklistProgress: "0/0",
        errors: []
    };

    // 1. Check Verification Checklist (Primary gate if exists)
    const checklistResult = verifyChecklist(directory);
    result.checklistComplete = checklistResult.passed;
    result.checklistProgress = checklistResult.progress;

    const hasChecklist = checklistResult.totalItems > 0;

    if (hasChecklist && !checklistResult.passed) {
        // Checklist exists but incomplete
        result.errors.push(`Verification checklist incomplete: ${checklistResult.progress}`);
        result.errors.push(...checklistResult.incompleteList.slice(0, 5).map(i => `  - ${i}`));
        if (checklistResult.incompleteList.length > 5) {
            result.errors.push(`  ... and ${checklistResult.incompleteList.length - 5} more`);
        }
    }

    // 2. Verify TODO completion (if no checklist, this is primary)
    const todoPath = join(directory, PATHS.TODO);
    if (existsSync(todoPath)) {
        try {
            const content = readFileSync(todoPath, 'utf-8');
            const incompleteCount = countMatches(content, TODO_INCOMPLETE_PATTERN);
            const completeCount = countMatches(content, TODO_COMPLETE_PATTERN);
            const total = incompleteCount + completeCount;

            result.todoIncomplete = incompleteCount;
            result.todoComplete = incompleteCount === 0 && total > 0;
            result.todoProgress = `${completeCount}/${total}`;

            if (!result.todoComplete && !hasChecklist) {
                if (total === 0) {
                    result.errors.push("No TODO items found - create tasks first");
                } else {
                    result.errors.push(
                        `TODO incomplete: ${result.todoProgress} (${incompleteCount} remaining)`
                    );
                }
            }
        } catch (error) {
            result.errors.push(`Failed to read TODO: ${error}`);
        }
    } else if (!hasChecklist) {
        result.errors.push(`TODO file not found at ${PATHS.TODO}`);
    }

    // 3. Verify sync issues are resolved (always checked)
    const syncPath = join(directory, PATHS.SYNC_ISSUES);
    if (existsSync(syncPath)) {
        try {
            const content = readFileSync(syncPath, 'utf-8');
            result.syncIssuesEmpty = !hasRealSyncIssues(content);

            if (!result.syncIssuesEmpty) {
                const issueLines = content.split('\n').filter(l =>
                    /^[-*]\s+\S/.test(l.trim()) || /ERROR|FAIL|CONFLICT/i.test(l)
                );
                result.syncIssuesCount = issueLines.length;
                result.errors.push(
                    `Sync issues not resolved: ${result.syncIssuesCount} issue(s) remain`
                );
            }
        } catch (error) {
            log(`[verification] Failed to read sync issues file: ${error}`);
            result.syncIssuesEmpty = true;
        }
    }

    // Final pass determination:
    // - If checklist exists: checklist must pass + sync issues must be empty
    // - If no checklist: TODO must be complete + sync issues must be empty
    if (hasChecklist) {
        result.passed = result.checklistComplete && result.syncIssuesEmpty;
    } else {
        result.passed = result.todoComplete && result.syncIssuesEmpty;
    }

    log("[verification] Mission verification result", {
        passed: result.passed,
        hasChecklist,
        checklistProgress: result.checklistProgress,
        todoProgress: result.todoProgress,
        syncIssuesEmpty: result.syncIssuesEmpty,
        errors: result.errors.length > 0 ? result.errors : undefined
    });

    return result;
}


export function buildVerificationFailurePrompt(result: VerificationResult): string {
    const errorList = result.errors.map(e => `❌ ${e}`).join('\n');
    const hasChecklist = result.checklistProgress !== "0/0";

    return `<verification_failure>
⚠️ **COMPLETION BLOCKED - Verification Failed**

Your attempt to finish was detected but the following checks **FAILED**:

${errorList}

## Current Status
| Check | Status | Details |
|-------|--------|---------|
${hasChecklist ? `| Checklist | ${result.checklistComplete ? '✅' : '❌'} | ${result.checklistProgress} verified |` : ''}
| TODO Progress | ${result.todoComplete ? '✅' : '❌'} | ${result.todoProgress} complete |
| Sync Issues | ${result.syncIssuesEmpty ? '✅' : '❌'} | ${result.syncIssuesCount} issue(s) |

## REQUIRED ACTIONS (DO NOT TRY TO FINISH AGAIN UNTIL RESOLVED)

${hasChecklist ? `1. **Complete Checklist**: \`cat ${CHECKLIST_FILE}\` - Check off ALL [ ] items
2. **Verify each item passes** before marking [x]` : `1. **Check TODO**: \`cat ${PATHS.TODO}\` - Find ALL [ ] items
2. **Complete remaining tasks** - Execute each incomplete item`}
3. **Check sync issues**: \`cat ${PATHS.SYNC_ISSUES}\` - Resolve any errors
4. **Verify builds/tests pass** - Run project build and test commands
5. **Only conclude when ALL conditions pass**

⚠️ The system will BLOCK premature completion every time. Work until truly complete.

**CONTINUE EXECUTING NOW** - Do not wait for user input.
</verification_failure>`;
}


export function buildTodoIncompletePrompt(result: VerificationResult): string {
    return `⚠️ **TODO Incomplete: ${result.todoProgress}**

${result.todoIncomplete} task(s) remaining. Continue working on incomplete items.

**REQUIRED**: Check .opencode/todo.md and complete ALL [ ] items before concluding.

\`\`\`bash
cat .opencode/todo.md
\`\`\`

**DO NOT** try to finish until ALL items are [x].`;
}



export function buildVerificationSummary(result: VerificationResult): string {
    const status = result.passed ? "✅ PASSED" : "❌ FAILED";
    const hasChecklist = result.checklistProgress !== "0/0";

    if (hasChecklist) {
        return `[Verification ${status}] Checklist: ${result.checklistProgress}, TODO: ${result.todoProgress}, Sync: ${result.syncIssuesEmpty ? 'clean' : result.syncIssuesCount + ' issues'}`;
    }
    return `[Verification ${status}] TODO: ${result.todoProgress}, Sync: ${result.syncIssuesEmpty ? 'clean' : result.syncIssuesCount + ' issues'}`;
}
