/**
 * SkillAssigner — automatic skill/MCP/hook assignment for DAG nodes.
 *
 * Analyzes node role, intent, and task characteristics to determine
 * the optimal set of skills, MCP servers, tools, and hooks.
 * Records the assignment decision to the unified decision trace store.
 */
import { createDecisionTraceStore } from "../evidence/decision-trace.js";
import { OMK_CORE_VERIFIED_PRESET, OMK_RELEASE_GUARD_PRESET, OMK_TS_PRODUCT_PRESET, OMK_WORKTREE_TEAM_PRESET, isCoreVerifiedIntent, isReleaseGuardIntent, isTsProductIntent, isWorktreeTeamIntent, } from "../runtime/core-verified-preset.js";
const ROLE_DEFAULTS = {
    explorer: { skills: ["omk-repo-explorer", "omk-context-broker", "omk-research-verify"], mcpServers: ["omk-project"], hooks: ["subagent-stop-audit.sh"] },
    researcher: { skills: ["omk-repo-explorer", "omk-research-verify", "omk-context-broker", "omk-plan-first"], mcpServers: ["omk-project", "context7"], hooks: ["subagent-stop-audit.sh"] },
    planner: { skills: ["omk-plan-first", "omk-context-broker", "omk-industrial-control-loop", "speckit-plan", "speckit-specify"], mcpServers: ["omk-project"], hooks: ["subagent-stop-audit.sh"] },
    architect: { skills: ["omk-plan-first", "omk-design-system", "omk-context-broker", "omk-industrial-control-loop"], mcpServers: ["omk-project", "context7"], hooks: ["subagent-stop-audit.sh"] },
    coder: { skills: ["omk-test-debug-loop", "omk-typescript-strict", "omk-python-typing", "omk-frontend-implementation", "matt-pocock-skills", "andrej-karpathy-skills", "omk-flow-feature-dev", "omk-flow-refactor"], mcpServers: ["omk-project"], hooks: ["protect-secrets.sh", "pre-shell-guard.sh", "post-format.sh"] },
    reviewer: { skills: ["omk-code-review", "omk-security-review", "omk-frontend-ui-review", "omk-backend-api-review", "omk-evidence-contract", "omk-multimodal-ui-review"], mcpServers: ["omk-project"], hooks: ["subagent-stop-audit.sh", "stop-verify.sh"] },
    security: { skills: ["omk-security-review", "omk-secret-guard", "omk-code-review", "omk-evidence-contract"], mcpServers: ["omk-project"], hooks: ["protect-secrets.sh", "pre-shell-guard.sh", "stop-verify.sh"] },
    qa: { skills: ["omk-quality-gate", "omk-test-debug-loop", "omk-typescript-strict", "omk-python-typing", "omk-evidence-contract"], mcpServers: ["omk-project"], hooks: ["stop-verify.sh", "pre-shell-guard.sh"] },
    tester: { skills: ["omk-quality-gate", "omk-test-debug-loop", "omk-flow-bugfix", "omk-evidence-contract"], mcpServers: ["omk-project"], hooks: ["stop-verify.sh", "pre-shell-guard.sh"] },
    integrator: { skills: ["omk-git-commit-pr", "omk-context-broker", "omk-evidence-contract"], mcpServers: ["omk-project"], hooks: ["branch-diff-snapshot.sh", "subagent-stop-audit.sh", "stop-verify.sh"] },
    aggregator: { skills: ["omk-code-review", "omk-context-broker", "omk-evidence-contract", "omk-industrial-control-loop"], mcpServers: ["omk-project"], hooks: ["subagent-stop-audit.sh", "stop-verify.sh"] },
    interviewer: { skills: ["omk-context-broker", "speckit-clarify", "speckit-checklist", "omk-plan-first"], mcpServers: ["omk-project"], hooks: ["subagent-stop-audit.sh"] },
    "vision-debugger": { skills: ["omk-multimodal-ui-review", "omk-design-md"], mcpServers: ["omk-project"], hooks: ["pre-shell-guard.sh"] },
    ontology: { skills: ["omk-context-broker", "graph-view", "agentmemory"], mcpServers: ["omk-project"], hooks: ["subagent-stop-audit.sh"] },
};
const SKILL_RULES = [
    {
        id: OMK_CORE_VERIFIED_PRESET.id,
        match: (_node, intent) => isCoreVerifiedIntent(intent),
        assign: {
            skills: [...OMK_CORE_VERIFIED_PRESET.skills],
            mcpServers: [...OMK_CORE_VERIFIED_PRESET.mcpServers],
            hooks: [...OMK_CORE_VERIFIED_PRESET.hooks],
        },
        priority: 10,
        rationale: OMK_CORE_VERIFIED_PRESET.purpose,
    },
    {
        id: OMK_TS_PRODUCT_PRESET.id,
        match: (node, intent) => isTsProductIntent(intent, `${node.id} ${node.name} ${node.role}`),
        assign: {
            skills: [...OMK_TS_PRODUCT_PRESET.skills],
            mcpServers: [...OMK_TS_PRODUCT_PRESET.mcpServers],
            hooks: [...OMK_TS_PRODUCT_PRESET.hooks],
        },
        priority: 20,
        rationale: OMK_TS_PRODUCT_PRESET.purpose,
    },
    {
        id: OMK_WORKTREE_TEAM_PRESET.id,
        match: (node, intent) => isWorktreeTeamIntent(intent, `${node.id} ${node.name} ${node.role}`),
        assign: {
            skills: [...OMK_WORKTREE_TEAM_PRESET.skills],
            mcpServers: [...OMK_WORKTREE_TEAM_PRESET.mcpServers],
            hooks: [...OMK_WORKTREE_TEAM_PRESET.hooks],
        },
        priority: 25,
        rationale: OMK_WORKTREE_TEAM_PRESET.purpose,
    },
    {
        id: OMK_RELEASE_GUARD_PRESET.id,
        match: (node, intent) => isReleaseGuardIntent(intent, `${node.id} ${node.name} ${node.role}`),
        assign: {
            skills: [...OMK_RELEASE_GUARD_PRESET.skills],
            mcpServers: [...OMK_RELEASE_GUARD_PRESET.mcpServers],
            hooks: [...OMK_RELEASE_GUARD_PRESET.hooks],
        },
        priority: 92,
        rationale: OMK_RELEASE_GUARD_PRESET.purpose,
    },
    {
        id: "web-design",
        match: (_node, intent) => ["coding", "documentation", "planning"].includes(intent) &&
            /web|page|landing|dashboard|prototype|ui|mockup|slide|deck|animation|visual|html|css|react/i.test(`${_node.name} ${_node.role}`),
        assign: { skills: ["web-design-engineer"] },
        priority: 90,
        rationale: "Visual front-end deliverable detected",
    },
    {
        id: "diagram-design",
        match: (_node, _intent) => /diagram|chart|flowchart|architecture|timeline|swimlane|quadrant|tree|layer|venn|pyramid|er\s*diagram/i.test(`${_node.name} ${_node.role}`),
        assign: { skills: ["diagram-design"] },
        priority: 95,
        rationale: "Diagram or chart generation detected",
    },
    {
        id: "kb-retriever",
        match: (_node, intent) => ["research", "planning"].includes(intent) &&
            /knowledge|kb|retrieve|search|pdf|excel|document|report/i.test(`${_node.name} ${_node.role}`),
        assign: { skills: ["kb-retriever"] },
        priority: 85,
        rationale: "Knowledge-base retrieval or document analysis detected",
    },
    {
        id: "code-review",
        match: (_node, intent) => intent === "review" ||
            /review|audit|check|validate|verify|pr\s*review/i.test(`${_node.name} ${_node.role}`),
        assign: { skills: ["omk-code-review", "omk-multimodal-ui-review"] },
        priority: 90,
        rationale: "Code or UI review task detected",
    },
    {
        id: "spec-driven",
        match: (_node, intent) => ["planning", "coding"].includes(intent) &&
            /spec|specify|plan|architecture|design.*doc|constitution/i.test(`${_node.name} ${_node.role}`),
        assign: { skills: ["speckit-specify", "speckit-plan", "omk-plan-first"] },
        priority: 80,
        rationale: "Specification or architecture planning detected",
    },
    {
        id: "security-audit",
        match: (_node, intent) => intent === "review" &&
            /security|audit|secret|vulnerability|auth|permission/i.test(`${_node.name} ${_node.role}`),
        assign: { skills: ["omk-flow-bugfix", "omk-code-review"] },
        priority: 95,
        rationale: "Security-sensitive review detected",
    },
    {
        id: "debugging",
        match: (_node, intent) => intent === "debugging" ||
            /debug|fix|error|failure|bug|trace|investigate/i.test(`${_node.name} ${_node.role}`),
        assign: { skills: ["omk-flow-bugfix"] },
        priority: 85,
        rationale: "Debugging or bug-fix task detected",
    },
    {
        id: "feature-dev",
        match: (_node, intent) => intent === "coding" &&
            /feature|implement|build|create|develop/i.test(`${_node.name} ${_node.role} ${_node.name}`),
        assign: { skills: ["omk-flow-feature-dev", "omk-design-md"] },
        priority: 80,
        rationale: "Feature development detected",
    },
    {
        id: "refactor",
        match: (_node, intent) => intent === "refactor" ||
            /refactor|optimize|clean|improve|simplify/i.test(`${_node.name} ${_node.role} ${_node.name}`),
        assign: { skills: ["omk-flow-refactor", "omk-flow-feature-dev"] },
        priority: 85,
        rationale: "Refactoring task detected",
    },
    {
        id: "release",
        match: (_node, _intent) => /release|deploy|publish|version|changelog|tag/i.test(`${_node.name} ${_node.role} ${_node.name}`),
        assign: { skills: ["omk-flow-release"] },
        priority: 90,
        rationale: "Release or deployment task detected",
    },
    {
        id: "team-run",
        match: (_node, _intent) => /team|parallel|multi.*agent|orchestrate|workflow/i.test(`${_node.name} ${_node.role} ${_node.name}`),
        assign: { skills: ["omk-flow-team-run", "omk-task-router"] },
        priority: 85,
        rationale: "Multi-agent team run detected",
    },
    {
        id: "mcp-required",
        match: (_node) => _node.routing?.requiresMcp === true,
        assign: { mcpServers: ["context7", "fetch", "filesystem-readonly"] },
        priority: 100,
        rationale: "Node explicitly requires MCP authority with read-only filesystem by default",
    },
    {
        id: "tool-calling",
        match: (_node) => _node.routing?.requiresToolCalling === true,
        assign: { tools: ["search", "read", "write"] },
        priority: 100,
        rationale: "Node explicitly requires tool calling",
    },
];
export function classifyNodeIntent(node) {
    const text = `${node.id} ${node.name} ${node.role}`.toLowerCase();
    if (/debug|fix|error|failure|bug|trace/.test(text) || node.role === "debugger")
        return "debugging";
    if (/review|audit|check|validate|verify/.test(text) || node.role === "reviewer")
        return "review";
    if (/test|spec|coverage|assertion/.test(text) || node.role === "tester")
        return "test-generation";
    if (/refactor|optimize|clean|improve|simplify/.test(text) || node.role === "refactor")
        return "refactor";
    if (/research|investigate|explore|search|discover|analyze/.test(text) || node.role === "researcher")
        return "research";
    if (/plan|design|architect|strategy|roadmap/.test(text) || node.role === "planner")
        return "planning";
    if (/doc|readme|changelog|comment/.test(text) || node.role === "documenter")
        return "documentation";
    if (/shell|command|run|exec|script/.test(text) || node.role === "shell")
        return "shell-operation";
    return "coding";
}
export function classifyRoutingIntent(input) {
    const text = `${input.id} ${input.name} ${input.role}`.toLowerCase();
    if (/debug|fix|error|failure|bug|trace/.test(text) || input.role === "debugger")
        return "debugging";
    if (/review|audit|check|validate|verify/.test(text) || input.role === "reviewer")
        return "review";
    if (/test|spec|coverage|assertion/.test(text) || input.role === "tester")
        return "test-generation";
    if (/refactor|optimize|clean|improve|simplify/.test(text) || input.role === "refactor")
        return "refactor";
    if (/research|investigate|explore|search|discover|analyze/.test(text) || input.role === "researcher")
        return "research";
    if (/plan|design|architect|strategy|roadmap/.test(text) || input.role === "planner")
        return "planning";
    if (/doc|readme|changelog|comment/.test(text) || input.role === "documenter")
        return "documentation";
    if (/shell|command|run|exec|script/.test(text) || input.role === "shell")
        return "shell-operation";
    return "coding";
}
export function assignSkills(arg, runId, attemptId) {
    if (isDagNode(arg)) {
        return doAssignSkills(arg, classifyNodeIntent(arg), runId, attemptId);
    }
    return doAssignSkillsForRoutingInput(arg, classifyRoutingIntent(arg), runId, attemptId);
}
function isDagNode(arg) {
    return "dependsOn" in arg;
}
function doAssignSkills(node, intent, runId, attemptId) {
    const nodeText = `${node.id} ${node.name} ${node.role}`;
    const matched = SKILL_RULES
        .filter((rule) => rule.match(node, intent))
        .sort((a, b) => b.priority - a.priority);
    return buildAssignment(matched, intent, nodeText, node.routing, runId, attemptId, node.id, ROLE_DEFAULTS[node.role]);
}
function doAssignSkillsForRoutingInput(input, intent, runId, attemptId) {
    const nodeText = `${input.id} ${input.name} ${input.role}`;
    // Adapt node shape for rule matching
    const adaptedNode = {
        id: input.id,
        name: input.name,
        role: input.role,
        dependsOn: [],
        status: "pending",
        retries: 0,
        maxRetries: 3,
        routing: input.routing ?? {},
    };
    const matched = SKILL_RULES
        .filter((rule) => rule.match(adaptedNode, intent))
        .sort((a, b) => b.priority - a.priority);
    return buildAssignment(matched, intent, nodeText, input.routing, runId, attemptId, input.id, ROLE_DEFAULTS[input.role]);
}
function buildAssignment(matched, intent, nodeText, routing, runId, attemptId, nodeId, roleDefaults) {
    const skills = new Set();
    const mcpServers = new Set();
    const tools = new Set();
    const hooks = new Set();
    const rationales = [];
    // Apply role defaults first (lowest priority; intent-specific rules override)
    if (roleDefaults) {
        if (roleDefaults.skills) {
            for (const s of roleDefaults.skills)
                skills.add(s);
        }
        if (roleDefaults.mcpServers) {
            for (const m of roleDefaults.mcpServers)
                mcpServers.add(m);
        }
        if (roleDefaults.tools) {
            for (const t of roleDefaults.tools)
                tools.add(t);
        }
        if (roleDefaults.hooks) {
            for (const h of roleDefaults.hooks)
                hooks.add(h);
        }
        rationales.push(`[role-default] Default capability set for ${nodeText.split(" ")[2] ?? ""}`);
    }
    for (const rule of matched) {
        if (rule.assign.skills) {
            for (const s of rule.assign.skills)
                skills.add(s);
        }
        if (rule.assign.mcpServers) {
            for (const m of rule.assign.mcpServers)
                mcpServers.add(m);
        }
        if (rule.assign.tools) {
            for (const t of rule.assign.tools)
                tools.add(t);
        }
        if (rule.assign.hooks) {
            for (const h of rule.assign.hooks)
                hooks.add(h);
        }
        rationales.push(`[${rule.id}] ${rule.rationale}`);
    }
    // Preserve manually assigned values
    if (routing?.skills) {
        for (const s of routing.skills)
            skills.add(s);
    }
    if (routing?.mcpServers) {
        for (const m of routing.mcpServers)
            mcpServers.add(m);
    }
    if (routing?.tools) {
        for (const t of routing.tools)
            tools.add(t);
    }
    if (routing?.hooks) {
        for (const h of routing.hooks)
            hooks.add(h);
    }
    const rationale = rationales.length > 0
        ? `Auto-assigned for intent=${intent}: ${rationales.join("; ")}`
        : `No auto-assignment for intent=${intent}`;
    const assignment = {
        skills: Array.from(skills),
        mcpServers: Array.from(mcpServers),
        tools: Array.from(tools),
        hooks: Array.from(hooks),
        rationale,
    };
    // Record decision trace
    if (runId && !runId.startsWith("local-")) {
        const traceStore = createDecisionTraceStore();
        traceStore.record(runId, {
            component: "skill-assigner",
            inputSummary: `node=${nodeId} role=${nodeText.split(" ")[2] ?? ""} intent=${intent}`,
            outputDecision: `skills=${assignment.skills.join(",")} mcp=${assignment.mcpServers.join(",")} tools=${assignment.tools.join(",")} hooks=${assignment.hooks.join(",")}`,
            reason: rationale,
            scores: { matchedRules: matched.length, priorityMax: matched[0]?.priority ?? 0 },
            nodeId,
            attemptId,
        });
    }
    return assignment;
}
export function applySkillAssignment(node, assignment) {
    return {
        ...node,
        routing: {
            ...node.routing,
            skills: [...assignment.skills],
            mcpServers: [...assignment.mcpServers],
            tools: [...assignment.tools],
            hooks: [...assignment.hooks],
            rationale: assignment.rationale,
            routeSource: "skill",
        },
    };
}
