import { inferTaskPhaseKey, parseKitPhaseNumberFromYaml, parseLeadingPhaseOrdinal } from "./phase-resolution.js";
import { isWishlistIntakeTask } from "./wishlist/wishlist-intake.js";
/**
 * Lower rank = sooner in the ready queue. Current phase, then next phase, then later phases, then past/unphased.
 */
export function workspacePhaseFocusRank(task, focus) {
    if (!focus) {
        return 0;
    }
    const taskKey = inferTaskPhaseKey(task);
    if (!taskKey) {
        return 50;
    }
    const cur = parseKitPhaseNumberFromYaml(focus.currentKitPhase) ??
        (focus.currentKitPhase?.trim() || null);
    const nxt = parseKitPhaseNumberFromYaml(focus.nextKitPhase) ?? (focus.nextKitPhase?.trim() || null);
    if (cur && taskKey === cur) {
        return 0;
    }
    if (nxt && taskKey === nxt) {
        return 1;
    }
    const tn = parseLeadingPhaseOrdinal(taskKey);
    const nc = parseLeadingPhaseOrdinal(cur);
    const nn = parseLeadingPhaseOrdinal(nxt);
    if (tn !== null && nc !== null && tn < nc) {
        return 40;
    }
    if (tn !== null && nn !== null && tn > nn) {
        return 20;
    }
    if (tn !== null && nc !== null && nxt && tn > nc) {
        return 10;
    }
    return 30;
}
/** Legacy recommendation ids (`imp-` + hex). New improvements use normal `T###` ids with `type: "improvement"`. */
const IMPROVEMENT_ID_RE = /^imp-[a-f0-9]+$/i;
export function isImprovementLikeTask(t) {
    if (t.type === "improvement") {
        return true;
    }
    return typeof t.id === "string" && IMPROVEMENT_ID_RE.test(t.id);
}
/** Canonical queue partition for filtered next-actions (`metadata.queueNamespace`); missing → `"default"`. */
export function getTaskQueueNamespace(task) {
    const meta = task.metadata;
    if (meta !== null && typeof meta === "object" && !Array.isArray(meta)) {
        const raw = meta.queueNamespace;
        if (typeof raw === "string" && raw.trim().length > 0) {
            return raw.trim();
        }
    }
    return "default";
}
export function filterTasksByQueueNamespace(tasks, queueNamespace) {
    const ns = typeof queueNamespace === "string" ? queueNamespace.trim() : "";
    if (!ns) {
        return tasks;
    }
    return tasks.filter((t) => getTaskQueueNamespace(t) === ns);
}
const PRIORITY_ORDER = {
    P1: 0,
    P2: 1,
    P3: 2
};
function priorityRank(task) {
    return PRIORITY_ORDER[task.priority ?? ""] ?? 99;
}
/** Deterministic ordering: workspace phase focus, priority rank, then task id. */
function sortReadyTasks(tasks, options) {
    const focus = options?.workspacePhaseFocus;
    return [...tasks].sort((a, b) => {
        const phaseR = workspacePhaseFocusRank(a, focus) - workspacePhaseFocusRank(b, focus);
        if (phaseR !== 0) {
            return phaseR;
        }
        const pr = priorityRank(a) - priorityRank(b);
        if (pr !== 0) {
            return pr;
        }
        return a.id.localeCompare(b.id);
    });
}
/**
 * Ready tasks whose dependsOn are all completed vs ready-but-blocked-by-deps.
 * Runnable tasks are listed first in `getNextActions.readyQueue`; `suggestedNext` is only ever runnable.
 */
function partitionReadyByDependencies(tasks, options) {
    const completedIds = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
    const readyCandidates = tasks.filter((t) => t.status === "ready" && !isWishlistIntakeTask(t));
    const runnableReady = [];
    const dependencyBlockedReady = [];
    for (const t of readyCandidates) {
        const deps = t.dependsOn ?? [];
        const depsSatisfied = deps.every((depId) => completedIds.has(depId));
        if (depsSatisfied) {
            runnableReady.push(t);
        }
        else {
            dependencyBlockedReady.push(t);
        }
    }
    return {
        runnableReady: sortReadyTasks(runnableReady, options),
        dependencyBlockedReady: sortReadyTasks(dependencyBlockedReady, options)
    };
}
function buildStateSummary(tasks) {
    const counts = {
        research: 0,
        proposed: 0,
        ready: 0,
        in_progress: 0,
        awaiting_review: 0,
        awaiting_policy_approval: 0,
        awaiting_external_decision: 0,
        blocked: 0,
        completed: 0,
        cancelled: 0
    };
    let total = 0;
    for (const task of tasks) {
        /** Wishlist intake (`wishlist_intake`) is ideation — tracked under the wishlist rollups, not the execution queue grid. */
        if (isWishlistIntakeTask(task)) {
            continue;
        }
        counts[task.status]++;
        total++;
    }
    return { ...counts, total };
}
function buildBlockingAnalysis(tasks) {
    const completedIds = new Set(tasks.filter((t) => t.status === "completed").map((t) => t.id));
    const entries = [];
    for (const task of tasks) {
        if (task.status !== "blocked")
            continue;
        const deps = task.dependsOn ?? [];
        const blockedBy = deps.filter((depId) => !completedIds.has(depId));
        if (blockedBy.length > 0) {
            entries.push({
                taskId: task.id,
                blockedBy,
                blockingCount: blockedBy.length
            });
        }
    }
    return entries.sort((a, b) => b.blockingCount - a.blockingCount);
}
export function getNextActions(tasks, options) {
    const scoped = filterTasksByQueueNamespace(tasks, options?.queueNamespace);
    const { runnableReady, dependencyBlockedReady } = partitionReadyByDependencies(scoped, options);
    const readyQueue = [...runnableReady, ...dependencyBlockedReady];
    return {
        readyQueue,
        suggestedNext: runnableReady[0] ?? null,
        stateSummary: buildStateSummary(scoped),
        blockingAnalysis: buildBlockingAnalysis(scoped)
    };
}
