import { workflowStore } from '../../../modules/orchestration/workflows/workflow-store.js';
import { orchestrationTaskService } from '../../../modules/orchestration/tasks/orchestration-task.service.js';
export const PIXCODE_TASK_RUN_GRAPH_PROTOCOL = 'pixcode.task-run-graph.v1';
function readString(value) {
    return typeof value === 'string' && value.trim() ? value.trim() : undefined;
}
function readRecord(value) {
    return value && typeof value === 'object' ? value : undefined;
}
function uniqueStrings(values) {
    return [...new Set(values.filter((value) => Boolean(value?.trim())))]
        .sort((a, b) => a.localeCompare(b));
}
function taskStatusPassed(status) {
    const normalized = String(status ?? '').toLocaleLowerCase('en');
    return normalized === 'done' || normalized === 'completed';
}
function taskStatusFailed(status) {
    const normalized = String(status ?? '').toLocaleLowerCase('en');
    return normalized === 'failed' || normalized === 'blocked' || normalized === 'cancelled' || normalized === 'canceled';
}
function criterionStatus(status) {
    if (taskStatusPassed(status))
        return 'passed';
    if (taskStatusFailed(status))
        return 'failed';
    return 'pending';
}
function taskmasterAcceptanceCriteria(taskmasterTask) {
    if (!taskmasterTask)
        return [];
    const criteria = [];
    const testStrategy = readString(taskmasterTask.testStrategy) ?? readString(taskmasterTask.test_strategy);
    if (testStrategy) {
        criteria.push({
            id: 'test-strategy',
            label: testStrategy,
            status: criterionStatus(taskmasterTask.status),
            source: 'taskmaster',
        });
    }
    const subtasks = Array.isArray(taskmasterTask.subtasks) ? taskmasterTask.subtasks : [];
    subtasks.forEach((subtask, index) => {
        const record = readRecord(subtask);
        if (!record)
            return;
        const title = readString(record.title);
        if (!title)
            return;
        criteria.push({
            id: `subtask-${readString(record.id) ?? index + 1}`,
            label: title,
            status: criterionStatus(record.status),
            source: 'taskmaster',
        });
    });
    return criteria;
}
function metadataTaskmasterId(run) {
    return readString(run.metadata?.taskmasterId)
        ?? readString(readRecord(run.metadata?.taskGraph)?.taskmasterId)
        ?? readString(readRecord(run.metadata?.replay)?.taskmasterId);
}
function metadataOrchestrationTaskId(run) {
    return readString(run.metadata?.orchestrationTaskId)
        ?? readString(readRecord(run.metadata?.taskGraph)?.orchestrationTaskId);
}
function artifactChangedFiles(node) {
    const files = [];
    if (node.handoffArtifact?.changedFiles) {
        files.push(...node.handoffArtifact.changedFiles);
    }
    for (const artifact of node.artifacts ?? []) {
        const data = readRecord(artifact.data);
        const metadata = readRecord(artifact.metadata);
        const candidates = [
            readString(metadata?.path),
            readString(metadata?.file),
            readString(data?.path),
            readString(data?.file),
        ];
        files.push(...candidates.filter((value) => Boolean(value)));
        for (const key of ['files', 'changedFiles']) {
            const value = data?.[key] ?? metadata?.[key];
            if (Array.isArray(value)) {
                files.push(...value.map((entry) => readString(entry)).filter((entry) => Boolean(entry)));
            }
        }
    }
    return uniqueStrings(files);
}
export function changedFilesFromWorkflowRun(run) {
    return uniqueStrings(run.nodeRuns.flatMap((node) => artifactChangedFiles(node)));
}
function workflowRunMatchesTask(run, task, taskmasterId) {
    const runTaskmasterId = metadataTaskmasterId(run);
    const runOrchestrationTaskId = metadataOrchestrationTaskId(run);
    if (taskmasterId && runTaskmasterId === taskmasterId)
        return true;
    if (task?.id && runOrchestrationTaskId === task.id)
        return true;
    if (task?.workflowRunIds?.includes(run.id))
        return true;
    return false;
}
function runSummary(run) {
    return {
        id: run.id,
        workflowId: run.workflowId,
        status: run.status,
        startedAt: run.startedAt,
        finishedAt: run.finishedAt,
        taskmasterId: metadataTaskmasterId(run),
        orchestrationTaskId: metadataOrchestrationTaskId(run),
        changedFiles: changedFilesFromWorkflowRun(run),
    };
}
export function buildTaskRunGraph({ projectId, taskmasterId, taskmasterTask, }) {
    const orchestrationTask = taskmasterId
        ? orchestrationTaskService.list(projectId).find((task) => task.taskmasterId === taskmasterId)
        : undefined;
    const workflowRuns = workflowStore
        .listRuns()
        .filter((run) => workflowRunMatchesTask(run, orchestrationTask, taskmasterId))
        .map(runSummary);
    const workflowCriteria = workflowRuns.map((run) => ({
        id: `run-${run.id}`,
        label: `Workflow ${run.workflowId} ${run.status}`,
        status: run.status === 'completed' ? 'passed' : run.status === 'failed' || run.status === 'canceled' ? 'failed' : 'pending',
        source: 'workflow',
    }));
    const acceptanceCriteria = [
        ...taskmasterAcceptanceCriteria(taskmasterTask),
        ...(orchestrationTask?.acceptanceCriteria ?? []),
        ...workflowCriteria,
    ];
    const changedFiles = uniqueStrings([
        ...(orchestrationTask?.changedFiles ?? []),
        ...workflowRuns.flatMap((run) => run.changedFiles),
    ]);
    return {
        protocol: PIXCODE_TASK_RUN_GRAPH_PROTOCOL,
        projectId,
        taskmasterId,
        orchestrationTaskId: orchestrationTask?.id,
        workflowRuns,
        changedFiles,
        acceptanceCriteria,
        status: {
            totalRuns: workflowRuns.length,
            completedRuns: workflowRuns.filter((run) => run.status === 'completed').length,
            failedRuns: workflowRuns.filter((run) => run.status === 'failed' || run.status === 'canceled').length,
            passedCriteria: acceptanceCriteria.filter((criterion) => criterion.status === 'passed').length,
            failedCriteria: acceptanceCriteria.filter((criterion) => criterion.status === 'failed').length,
        },
    };
}
//# sourceMappingURL=task-run-graph.js.map