import * as fs from 'fs/promises';
import * as path from 'path';
export const USER_WORKFLOW_TRACE_FILE = 'user-workflow-trace.json';
function short(value, limit = 220) {
    const text = String(value ?? '').replace(/\s+/g, ' ').trim();
    return text.length > limit ? `${text.slice(0, Math.max(0, limit - 1))}...` : text;
}
function uniqueStrings(values) {
    return [...new Set(values.map((value) => String(value ?? '').trim()).filter(Boolean))];
}
function workerStatus(worker) {
    if (worker.budgetExceeded)
        return 'warn';
    if (worker.verified)
        return 'ok';
    if (worker.outcome === 'failed')
        return 'failed';
    if (worker.outcome === 'partial')
        return 'warn';
    if (!String(worker.diff ?? '').trim() && !(worker.commandRecords ?? []).length)
        return 'skipped';
    return 'warn';
}
function verificationStatus(entry) {
    if (entry.status === 'passed' || entry.passed === true)
        return 'ok';
    if (entry.status === 'skipped')
        return 'skipped';
    return 'failed';
}
function extractActions(run) {
    const manifestActions = (run.workerManifests ?? [])
        .flatMap((manifest) => manifest.actions ?? [])
        .map((action) => action.command ?? action.type ?? action.name ?? action.tool ?? JSON.stringify(action));
    const commandRecords = (run.workerResults ?? [])
        .flatMap((worker) => worker.commandRecords ?? [])
        .map((record) => record.command);
    return uniqueStrings([...manifestActions, ...commandRecords]).slice(0, 30);
}
function extractVerifyCommands(run) {
    const manifestCommands = (run.workerManifests ?? []).flatMap((manifest) => manifest.verifyCommands ?? []);
    const verificationCommands = (run.verificationResults ?? [])
        .flatMap((entry) => entry.commands ?? [])
        .map((record) => record.command);
    return uniqueStrings([...manifestCommands, ...verificationCommands]).slice(0, 30);
}
function buildSignals(run) {
    const signals = [];
    const workers = run.workerResults ?? [];
    const verifications = run.verificationResults ?? [];
    const modifiedFiles = workers.reduce((sum, worker) => sum + (worker.modifiedFiles?.length ?? 0), 0);
    const hasDiff = workers.some((worker) => String(worker.diff ?? '').trim().length > 0);
    const commandOnly = workers.some((worker) => (worker.commandRecords ?? []).length > 0);
    const failedWorkers = workers.filter((worker) => workerStatus(worker) === 'failed');
    const skippedVerifications = verifications.filter((entry) => entry.status === 'skipped');
    const failedVerifications = verifications.filter((entry) => verificationStatus(entry) === 'failed');
    if (String(run.state) === 'failed') {
        signals.push({
            code: 'workflow_failed',
            severity: 'high',
            summary: short(run.result || 'Agent workflow failed before a stable user outcome was produced.'),
            evidence: { state: run.state },
        });
    }
    if (workers.length === 0) {
        signals.push({
            code: 'no_agent_workers',
            severity: 'warn',
            summary: 'No worker results were recorded for this user workflow.',
        });
    }
    if (failedWorkers.length > 0) {
        signals.push({
            code: 'agent_worker_failed',
            severity: 'high',
            summary: `${failedWorkers.length} worker(s) failed or returned unusable output.`,
            evidence: { workers: failedWorkers.map((worker) => worker.workerId).slice(0, 10) },
        });
    }
    if (failedVerifications.length > 0) {
        signals.push({
            code: 'verification_failed',
            severity: 'high',
            summary: `${failedVerifications.length} verification step(s) failed.`,
            evidence: { workers: failedVerifications.map((entry) => entry.workerId).slice(0, 10) },
        });
    }
    if (!hasDiff && modifiedFiles === 0 && (skippedVerifications.length > 0 || commandOnly)) {
        signals.push({
            code: 'no_applicable_diff',
            severity: String(run.state) === 'failed' ? 'warn' : 'info',
            summary: 'Agents produced no repository patch; this is expected for read-only or command-only workflows.',
            evidence: { skippedVerifications: skippedVerifications.length, commandOnly },
        });
    }
    const tokenTelemetry = run.tokenTelemetry ?? {};
    const grossTokens = Number(tokenTelemetry.grossInputTokens ?? 0);
    const savedTokens = Number(tokenTelemetry.savedTokens ?? 0);
    if (grossTokens > 80_000 && savedTokens < grossTokens * 0.2) {
        signals.push({
            code: 'token_pressure',
            severity: 'warn',
            summary: 'Workflow used a large context budget with low compression savings.',
            evidence: { grossInputTokens: grossTokens, savedTokens },
        });
    }
    return signals;
}
function buildNextActions(trace) {
    if (trace.signals.length === 0) {
        return ['Use this trace as the stable replay/eval baseline for similar user workflows.'];
    }
    const actions = new Set();
    for (const signal of trace.signals) {
        if (signal.code === 'workflow_failed' || signal.code === 'agent_worker_failed') {
            actions.add('Inspect the failed worker span, then replay with narrower files, clearer success criteria, or a better specialist.');
        }
        if (signal.code === 'verification_failed') {
            actions.add('Promote the failing verification commands into a regression eval before rerunning.');
        }
        if (signal.code === 'no_applicable_diff') {
            actions.add('If a patch was expected, rerun with mutate intent and explicit target files; otherwise treat this as a read-only trace.');
        }
        if (signal.code === 'token_pressure') {
            actions.add('Run token optimization first and replay with a smaller context packet.');
        }
    }
    return [...actions].slice(0, 5);
}
export function buildUserWorkflowTrace(run) {
    const planner = run.plannerResult ?? {};
    const selectedFiles = uniqueStrings(planner.selectedFiles ?? []);
    const selectedSkills = uniqueStrings([
        ...(planner.selectedSkills ?? []),
        ...(run.activeSkills ?? []).map((skill) => skill.name),
    ]);
    const selectedWorkflows = uniqueStrings([
        ...(planner.selectedWorkflows ?? []),
        ...(run.activeWorkflows ?? []).map((workflow) => workflow.name),
    ]);
    const selectedSpecialists = uniqueStrings([
        ...(planner.selectedSpecialists ?? []).map((specialist) => specialist.name ?? specialist.specialistId),
        ...(run.workerManifests ?? []).map((manifest) => manifest.specialistName ?? manifest.specialistId),
    ]);
    const actions = extractActions(run);
    const verifyCommands = extractVerifyCommands(run);
    const spans = [
        {
            id: 'user-goal',
            kind: 'user_goal',
            label: 'User goal',
            status: 'ok',
            summary: short(run.goal, 320),
            attributes: {
                parentRunId: run.parentRunId ?? null,
                sourceAutomationId: run.sourceAutomationId ?? null,
            },
        },
        {
            id: 'planning',
            parentId: 'user-goal',
            kind: 'planning',
            label: 'Agent plan',
            status: selectedSpecialists.length > 0 || selectedSkills.length > 0 ? 'ok' : 'warn',
            summary: short(planner.summary ?? 'Planner selected agents, skills, workflows, and files for the user workflow.'),
            attributes: { selectedSkills, selectedWorkflows, selectedSpecialists },
        },
        {
            id: 'context',
            parentId: 'planning',
            kind: 'context',
            label: 'Context packet',
            status: selectedFiles.length > 0 ? 'ok' : 'warn',
            summary: `${selectedFiles.length} file(s), ${selectedSkills.length} skill(s), ${selectedWorkflows.length} workflow(s) routed into the agent workflow.`,
            attributes: {
                selectedFiles,
                memoryChecks: run.memoryChecks?.length ?? 0,
                tokenTelemetry: run.tokenTelemetry ?? null,
            },
        },
        ...(run.workerResults ?? []).map((worker) => ({
            id: `worker-${worker.workerId ?? 'unknown'}`,
            parentId: 'planning',
            kind: 'agent_action',
            label: `${worker.role ?? 'worker'} ${worker.workerId ?? 'unknown'}`,
            status: workerStatus(worker),
            summary: short(worker.summary ?? worker.learned ?? worker.outcome ?? 'Agent worker completed.'),
            attributes: {
                workerId: worker.workerId,
                role: worker.role,
                outcome: worker.outcome,
                verified: Boolean(worker.verified),
                modifiedFiles: worker.modifiedFiles ?? [],
                commandCount: worker.commandRecords?.length ?? 0,
                tokensUsed: worker.tokensUsed ?? null,
            },
        })),
        ...(run.verificationResults ?? []).map((entry) => ({
            id: `verification-${entry.verifierId ?? entry.workerId ?? 'unknown'}`,
            parentId: `worker-${entry.workerId ?? 'unknown'}`,
            kind: 'verification',
            label: `Verification for ${entry.workerId ?? 'worker'}`,
            status: verificationStatus(entry),
            summary: short(entry.summary ?? 'Verification completed.'),
            attributes: {
                workerId: entry.workerId,
                verifierId: entry.verifierId,
                commandCount: entry.commands?.length ?? 0,
                skippedReason: entry.skippedReason ?? null,
            },
        })),
        {
            id: 'decision',
            parentId: 'planning',
            kind: 'decision',
            label: 'Merge decision',
            status: run.finalDecision?.action === 'apply' ? 'ok' : run.finalDecision?.action ? 'warn' : 'skipped',
            summary: short(run.finalDecision?.recommendedStrategy ?? run.finalDecision?.action ?? 'No merge decision recorded.'),
            attributes: {
                action: run.finalDecision?.action ?? null,
                winner: run.finalDecision?.winner?.workerId ?? null,
            },
        },
        {
            id: 'outcome',
            parentId: 'decision',
            kind: 'outcome',
            label: 'User workflow outcome',
            status: String(run.state) === 'failed' ? 'failed' : 'ok',
            summary: short(run.result ?? ''),
            attributes: {
                state: run.state,
                promotions: run.promotionDecisions?.length ?? 0,
                continuationChildren: run.continuationChildren?.length ?? 0,
            },
        },
    ];
    const signals = buildSignals(run);
    const trace = {
        schemaVersion: 1,
        scope: 'user-agent-workflow',
        traceId: `uwt_${run.runId}`,
        runId: String(run.runId ?? ''),
        generatedAt: Date.now(),
        goal: String(run.goal ?? ''),
        state: String(run.state ?? ''),
        result: String(run.result ?? ''),
        artifactsPath: run.artifactsPath,
        userJourney: {
            goal: String(run.goal ?? ''),
            selectedFiles,
            selectedSkills,
            selectedWorkflows,
            selectedSpecialists,
            actions,
            verifyCommands,
        },
        spans,
        signals,
        nextActions: [],
    };
    trace.nextActions = buildNextActions(trace);
    return trace;
}
export function resolveUserWorkflowTracePath(artifactsPath) {
    return path.join(artifactsPath, USER_WORKFLOW_TRACE_FILE);
}
export async function readUserWorkflowTrace(artifactsPath) {
    try {
        const raw = await fs.readFile(resolveUserWorkflowTracePath(artifactsPath), 'utf8');
        return JSON.parse(raw);
    }
    catch {
        return undefined;
    }
}
export function summarizeUserWorkflowTrace(trace) {
    const high = trace.signals.filter((signal) => signal.severity === 'high').length;
    const warns = trace.signals.filter((signal) => signal.severity === 'warn').length;
    return `${trace.state.toUpperCase()} user workflow · ${trace.spans.length} span(s) · ${high} high signal(s), ${warns} warning(s)`;
}
