/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { existsSync, readdirSync } from 'node:fs';
import { join } from 'node:path';
import { listTasks } from './task-state.js';
import { readWorkspaceConfig } from './workspace-config.js';
import { listWorkflowRuns } from './workflow-state.js';
import { listRecords } from './orchestration-records.js';
export function getOfflineStatus(cwd) {
    const config = readWorkspaceConfig(cwd);
    const tasks = listTasks(cwd);
    const activeTask = tasks.find((t) => t.status === 'claimed') ?? tasks.find((t) => t.status === 'open') ?? null;
    const runs = listWorkflowRuns(cwd);
    const activeRun = runs.find((r) => r.status === 'running') ?? runs.find((r) => r.status === 'paused') ?? null;
    const currentPhase = resolveCurrentPhase(activeRun);
    const lastHandoff = resolveLastHandoff(cwd, activeTask);
    const evidenceGaps = resolveEvidenceGaps(cwd, activeTask, activeRun);
    const cachedResources = listCachedResources(cwd);
    const suggestedCommands = buildSuggestedCommands(activeTask, activeRun, currentPhase);
    const localLlmAvailable = detectLocalLlm();
    return {
        config,
        activeTask,
        activeRun,
        currentPhase,
        lastHandoff,
        evidenceGaps,
        cachedResources,
        suggestedCommands,
        localLlmAvailable,
    };
}
export function getOfflineGuide(cwd, taskId) {
    const tasks = listTasks(cwd);
    const task = tasks.find((t) => t.id === taskId) ?? null;
    const runs = listWorkflowRuns(cwd);
    const run = runs.find((r) => r.storyId === taskId && (r.status === 'running' || r.status === 'paused')) ?? null;
    const phase = resolveCurrentPhase(run);
    const steps = buildGuideSteps(task, run, phase);
    const references = collectReferences(cwd, task, phase);
    const commands = buildGuideCommands(taskId, task, run, phase);
    return { taskId, task, run, phase, steps, references, commands };
}
// ─── OFFLINE.md runbook generation ──────────────────────────────────────────
export function generateOfflineRunbook(cwd) {
    const config = readWorkspaceConfig(cwd);
    const profiles = config?.profiles ?? [];
    const lines = [
        '# Offline Recovery Runbook',
        '',
        '> Auto-generated by setup-agents. Do not edit manually.',
        '',
        '## Quick Reference',
        '',
        '```bash',
        '# Check offline status',
        'sf setup-agents offline status --json',
        '',
        '# Get deterministic guide for active task',
        'sf setup-agents offline guide --task <id>',
        '',
        '# Resume workflow after connectivity restored',
        'sf setup-agents workflow run --task <id> --resume <run-id>',
        '```',
        '',
        '## Available Context Sources',
        '',
        '### 1. Local Repository',
        '- Source code, metadata, tests in working directory',
        '- Git history: `git log --oneline -20`',
        '- Recent changes: `git diff HEAD~3`',
        '',
        '### 2. Workflow State',
        '- Tasks: `.setup-agents/state/tasks.jsonl`',
        '- Workflow runs: `.setup-agents/state/workflow-runs.jsonl`',
        '- Evidence: `.setup-agents/state/evidence.jsonl`',
        '- Decisions: `.setup-agents/state/decisions.jsonl`',
        '- Handoffs: `.setup-agents/state/handoffs.jsonl`',
        '',
        '### 3. Generated Prompts & Lessons',
        '- Prompt registry: `.generated-prompts/`',
        '- Skills: `.setup-agents/skills/`',
        '- Playbooks: `.setup-agents/playbooks/`',
        '',
        '### 4. Profile Resources',
    ];
    for (const profile of profiles) {
        lines.push(`- ${profile}: rules + capabilities configured`);
    }
    lines.push('', '### 5. Cached Resources', '- Check `.setup-agents/cache/` for previously fetched external docs', '', '## Phase Recovery Procedures', '');
    const phaseList = ['pm', 'ba', 'architect', 'developer', 'qa', 'release'];
    for (const phase of phaseList) {
        lines.push(`### ${phase}`, '');
        lines.push(...getPhaseRecoverySteps(phase));
        lines.push('');
    }
    lines.push('## Local LLM Configuration (Optional)', '', 'If you have a local LLM runtime available, configure it in `.setup-agents/config.json`:', '', '```json', '{', '  "localLlm": {', '    "endpoint": "http://localhost:11434/v1",', '    "model": "llama3.2",', '    "provider": "ollama"', '  }', '}', '```', '', 'Supported providers: ollama, llama.cpp, vLLM, LM Studio, or any OpenAI-compatible endpoint.', '');
    return lines.join('\n');
}
// ─── Helpers ────────────────────────────────────────────────────────────────
function resolveCurrentPhase(run) {
    if (!run)
        return null;
    const running = run.phases.find((p) => p.status === 'running');
    if (running)
        return running.phase;
    const lastDone = [...run.phases].reverse().find((p) => p.status === 'done');
    if (!lastDone)
        return run.phases[0]?.phase ?? null;
    const idx = run.phases.indexOf(lastDone);
    return run.phases[idx + 1]?.phase ?? null;
}
function resolveLastHandoff(cwd, task) {
    if (!task)
        return null;
    const handoffs = listRecords(cwd, 'handoff');
    const taskHandoffs = handoffs.filter((h) => h.taskIds.includes(task.id));
    if (taskHandoffs.length === 0)
        return null;
    const last = taskHandoffs[taskHandoffs.length - 1];
    return { id: last.id, from: last.from, to: last.to, createdAt: last.createdAt };
}
function resolveEvidenceGaps(cwd, task, run) {
    if (!task || !run)
        return [];
    const evidence = listRecords(cwd, 'evidence');
    const taskEvidence = evidence.filter((e) => e.taskIds.includes(task.id));
    const gaps = [];
    for (const phase of run.phases) {
        if (phase.status === 'done') {
            const phaseEvidence = taskEvidence.filter((e) => e.owner?.includes(phase.phase));
            if (phaseEvidence.length === 0) {
                gaps.push(`${phase.phase}: no evidence recorded`);
            }
        }
    }
    return gaps;
}
function listCachedResources(cwd) {
    const cacheDir = join(cwd, '.setup-agents', 'cache');
    if (!existsSync(cacheDir))
        return [];
    try {
        return readdirSync(cacheDir).filter((f) => !f.startsWith('.'));
    }
    catch {
        return [];
    }
}
function buildSuggestedCommands(task, run, phase) {
    const commands = [];
    if (!task) {
        commands.push('sf setup-agents task list --json');
        return commands;
    }
    if (task.status === 'open') {
        commands.push(`sf setup-agents task claim --id ${task.id}`);
    }
    if (run && phase) {
        if (run.status === 'paused') {
            commands.push(`sf setup-agents workflow run --task ${task.id} --resume ${run.id}`);
        }
        commands.push(`sf setup-agents evidence add --task ${task.id} --role ${phase} --type command --summary "..."`);
    }
    if (!run && task.status === 'claimed') {
        commands.push(`sf setup-agents workflow run --task ${task.id}`);
    }
    return commands;
}
function detectLocalLlm() {
    const endpoints = ['http://localhost:11434', 'http://localhost:1234', 'http://localhost:8080'];
    for (const endpoint of endpoints) {
        try {
            const url = new URL('/v1/models', endpoint);
            return existsSync(url.pathname) || true;
        }
        catch {
            // not reachable — that's fine offline
        }
    }
    return false;
}
function buildGuideSteps(task, run, phase) {
    if (!task)
        return ['No task found. Run `sf setup-agents task list` to see available tasks.'];
    const steps = [];
    if (task.status === 'open') {
        steps.push('1. Claim the task: `sf setup-agents task claim --id ' + task.id + '`');
    }
    if (!run) {
        steps.push(`${steps.length + 1}. Start workflow: \`sf setup-agents workflow run --task ${task.id}\``);
    }
    else if (phase) {
        steps.push(`${steps.length + 1}. Current phase: **${phase}**`);
        steps.push(...getPhaseRecoverySteps(phase).map((s, i) => `${steps.length + i + 1}. ${s}`));
    }
    steps.push(`${steps.length + 1}. Record evidence when done`);
    return steps;
}
function collectReferences(cwd, task, phase) {
    const refs = [];
    const playbooksDir = join(cwd, '.setup-agents', 'playbooks');
    if (existsSync(playbooksDir)) {
        try {
            const playbooks = readdirSync(playbooksDir).filter((f) => f.endsWith('.md'));
            if (phase) {
                const phasePlaybook = playbooks.find((p) => p.includes(phase));
                if (phasePlaybook)
                    refs.push(join(playbooksDir, phasePlaybook));
            }
            refs.push(...playbooks.slice(0, 3).map((p) => join(playbooksDir, p)));
        }
        catch {
            // ignore
        }
    }
    const skillsDir = join(cwd, '.setup-agents', 'skills');
    if (existsSync(skillsDir)) {
        try {
            const skills = readdirSync(skillsDir);
            refs.push(...skills.slice(0, 3).map((s) => join(skillsDir, s, 'SKILL.md')));
        }
        catch {
            // ignore
        }
    }
    if (task) {
        const decisions = listRecords(cwd, 'decision');
        const taskDecisions = decisions.filter((d) => d.taskIds.includes(task.id));
        for (const d of taskDecisions.slice(0, 3)) {
            refs.push(`Decision: ${d.summary}`);
        }
    }
    return [...new Set(refs)];
}
function buildGuideCommands(taskId, task, run, phase) {
    const cmds = [];
    if (task && task.status === 'open') {
        cmds.push(`sf setup-agents task claim --id ${taskId}`);
    }
    if (run && run.status === 'paused') {
        cmds.push(`sf setup-agents workflow run --task ${taskId} --resume ${run.id}`);
    }
    if (phase) {
        cmds.push(`sf setup-agents evidence add --task ${taskId} --role ${phase} --type command --summary "..."`);
        cmds.push(`sf setup-agents review request --task ${taskId} --role ${phase}`);
    }
    if (!run && task) {
        cmds.push(`sf setup-agents workflow run --task ${taskId}`);
    }
    cmds.push(`sf setup-agents task view --id ${taskId} --json`);
    return cmds;
}
function getPhaseRecoverySteps(phase) {
    switch (phase) {
        case 'pm':
            return [
                'Review task goals and acceptance criteria',
                'Check `.setup-agents/state/tasks.jsonl` for context',
                'Validate story decomposition is complete',
            ];
        case 'ba':
            return [
                'Review requirements in task description',
                'Check story mapping artifacts in `.setup-agents/skills/story-mapping/`',
                'Verify acceptance criteria coverage',
            ];
        case 'architect':
            return [
                'Review decisions in `.setup-agents/state/decisions.jsonl`',
                'Check architecture docs in `docs/`',
                'Validate technical approach aligns with constraints',
            ];
        case 'ux':
            return [
                'Review UX standards in profile rules',
                'Check component accessibility (contrast, touch targets)',
                'Validate empty states and loading patterns',
            ];
        case 'developer':
            return [
                'Read source code for context: `git log --oneline -10`',
                'Check test coverage: run local tests',
                'Follow coding standards from profile rules',
                'Record evidence: commands run, files modified',
            ];
        case 'security-review':
            return ['Run Code Analyzer: `sf scanner run`', 'Check FLS/CRUD enforcement', 'Validate no hardcoded credentials'];
        case 'qa':
            return [
                'Run test suite locally',
                'Verify acceptance criteria from task',
                'Record test results as evidence',
                'Check for regressions',
            ];
        case 'release':
            return [
                'Validate deployment: `sf project deploy validate`',
                'Check release checklist',
                'Verify all evidence and reviews recorded',
            ];
    }
}
//# sourceMappingURL=offline-recovery.js.map