"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildWorkerTemplateDraftContract = buildWorkerTemplateDraftContract;
exports.validateWorkerTemplateDraftSemanticRules = validateWorkerTemplateDraftSemanticRules;
const zod_1 = require("zod");
const types_1 = require("../workflows/types");
const template_contract_support_1 = require("./template-contract-support");
const validation_issues_1 = require("./validation-issues");
const workerTemplateDraftSchema = zod_1.z
    .discriminatedUnion("action", [
    zod_1.z
        .object({
        action: zod_1.z.literal("create_new"),
        path: zod_1.z
            .string()
            .min(1)
            .describe("Normalized relative workflow template path ending in .md with no whitespace."),
        ...template_contract_support_1.WORKER_TEMPLATE_CONTENT_SCHEMA_SHAPE,
    })
        .strict(),
    zod_1.z
        .object({
        action: zod_1.z.literal("update_existing"),
        targetPath: zod_1.z
            .string()
            .min(1)
            .describe("Existing workflow template path to update."),
        path: zod_1.z
            .string()
            .min(1)
            .describe("Final normalized workflow template path after the update. Use targetPath unless template-set mode is deliberately moving the template."),
        ...template_contract_support_1.WORKER_TEMPLATE_CONTENT_SCHEMA_SHAPE,
        impactSummary: zod_1.z
            .string()
            .min(1)
            .describe("Concise summary of expected impact on referrers."),
    })
        .strict(),
    zod_1.z
        .object({
        action: zod_1.z.literal("reuse_existing"),
        targetPath: zod_1.z
            .string()
            .min(1)
            .describe("Existing workflow template path to reuse without edits."),
        reason: zod_1.z.string().min(1).describe("Why the existing template fits."),
    })
        .strict(),
])
    .transform((draft) => {
    if (draft.action === "reuse_existing") {
        return draft;
    }
    const rest = { ...draft };
    delete rest.requires;
    return {
        ...rest,
        ...(0, template_contract_support_1.normalizeWorkerTemplateContentInput)(draft),
    };
})
    .describe("Workflow template authoring decision.");
const workerTemplateSetDraftSchema = zod_1.z
    .object({
    items: zod_1.z
        .array(workerTemplateDraftSchema)
        .min(1)
        .describe("Ordered workflow template create/update/reuse decisions."),
})
    .strict()
    .describe("Workflow template set authoring decision.");
function buildWorkerTemplateDraftContract(input) {
    const schema = (input.templateSet ? workerTemplateSetDraftSchema : workerTemplateDraftSchema);
    return (0, template_contract_support_1.buildWorkerTemplateContract)({
        schema,
        example: buildWorkerTemplateDraftExample(input),
        rules: buildWorkerTemplateDraftRules(),
    });
}
function validateWorkerTemplateDraftSemanticRules(draft, input) {
    if (isWorkerTemplateSetDraft(draft)) {
        return validateWorkerTemplateSetDraftSemanticRules(draft, input);
    }
    if (input.templateSet === true) {
        return [
            (0, validation_issues_1.createWorkerSemanticValidationIssue)({
                path: [],
                message: "template-set mode must return an items array.",
            }),
        ];
    }
    return validateSingleWorkerTemplateDraftSemanticRules(draft, input);
}
function validateWorkerTemplateSetDraftSemanticRules(draft, input) {
    const issues = [];
    const knownCreatedPaths = collectCreatedWorkflowTemplatePaths(draft.items);
    const knownCreatedTemplates = collectCreatedWorkflowTemplateEntries(draft.items);
    for (const [index, item] of draft.items.entries()) {
        const { explicitTemplateOverrides: _explicitTemplateOverrides, ...baseInput } = input;
        const itemInput = {
            ...baseInput,
            existingWorkflowTemplatePaths: input.existingWorkflowTemplatePaths,
            additionalWorkflowTemplatePaths: knownCreatedPaths,
            additionalWorkflowTemplates: knownCreatedTemplates,
        };
        const itemIssues = validateSingleWorkerTemplateDraftSemanticRules(item, itemInput).map((issue) => (0, validation_issues_1.prefixWorkerValidationIssuePath)(["items", index], issue));
        (0, validation_issues_1.appendWorkerValidationIssues)(issues, itemIssues);
    }
    const duplicatePathIssues = findDuplicateTemplateDecisionPaths(draft.items);
    (0, validation_issues_1.appendWorkerValidationIssues)(issues, duplicatePathIssues);
    (0, validation_issues_1.appendWorkerValidationIssues)(issues, validateAnchorTemplateSetItem(draft, input));
    return issues;
}
function validateAnchorTemplateSetItem(draft, input) {
    if (input.anchorTemplate === undefined) {
        return [];
    }
    const anchorIndex = draft.items.findIndex((item) => {
        if (item.action !== "update_existing" && item.action !== "reuse_existing") {
            return false;
        }
        return item.targetPath === input.anchorTemplate?.path;
    });
    if (anchorIndex >= 0) {
        return [];
    }
    return [
        (0, validation_issues_1.createWorkerSemanticValidationIssue)({
            path: ["items"],
            message: `template-set updates must include anchor template ${input.anchorTemplate.path} as update_existing or reuse_existing.`,
        }),
    ];
}
function validateSingleWorkerTemplateDraftSemanticRules(draft, input) {
    const issues = [];
    if (input.explicitTemplateOverrides?.path !== undefined &&
        draft.action !== "create_new") {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path: ["action"],
            message: "action must be create_new when an explicit path override is provided.",
        });
    }
    if (draft.action === "reuse_existing" &&
        (Object.hasOwn(input.explicitTemplateOverrides ?? {}, "description") ||
            input.explicitTemplateOverrides?.requiredSkills !== undefined ||
            input.explicitTemplateOverrides?.requiredMcp !== undefined ||
            input.explicitTemplateOverrides?.targets !== undefined ||
            input.explicitTemplateOverrides?.autoSelect !== undefined)) {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path: ["action"],
            message: "action must not be reuse_existing when explicit metadata overrides are provided.",
        });
    }
    if (draft.action === "reuse_existing") {
        validateExistingTemplatePath(draft.targetPath, ["targetPath"], input, issues);
        return issues;
    }
    const effectivePath = draft.action === "create_new"
        ? (input.explicitTemplateOverrides?.path ?? draft.path)
        : draft.path;
    const normalizedPath = (0, types_1.normalizeWorkflowTemplatePath)(effectivePath);
    const effectiveRequiredSkills = input.explicitTemplateOverrides?.requiredSkills ?? draft.requiredSkills;
    const effectiveRequiredMcp = input.explicitTemplateOverrides?.requiredMcp ?? draft.requiredMcp;
    if (normalizedPath !== effectivePath) {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path: ["path"],
            message: (0, types_1.isReservedWorkflowTemplateSelectorValue)(effectivePath)
                ? "path must not use reserved workflow selector values."
                : "path must be a normalized relative .md path with no whitespace.",
        });
    }
    else {
        if (draft.action === "create_new" &&
            input.existingWorkflowTemplatePaths.includes(effectivePath)) {
            (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
                path: ["path"],
                message: "path must not already exist in the repository.",
            });
        }
        if (draft.action === "update_existing") {
            validateExistingTemplatePath(draft.targetPath, ["targetPath"], input, issues);
            if (draft.path !== draft.targetPath && input.templateSet !== true) {
                (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
                    path: ["path"],
                    message: "path must equal targetPath unless template-set mode is enabled.",
                });
            }
            if (draft.path !== draft.targetPath &&
                input.existingWorkflowTemplatePaths.includes(draft.path)) {
                (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
                    path: ["path"],
                    message: "path must not already exist in the repository.",
                });
            }
        }
    }
    (0, validation_issues_1.appendWorkerValidationIssues)(issues, (0, template_contract_support_1.validateWorkerTemplateContentSemanticRules)({
        body: draft.body,
        requiredSkills: effectiveRequiredSkills,
        requiredMcp: effectiveRequiredMcp,
        frontmatterMessage: "body must not include YAML frontmatter. Put path and description in the top-level draft fields.",
        validateBodyStructure: () => validateWorkerTemplateDraftBodyStructure(draft, input),
    }));
    return issues;
}
function isWorkerTemplateSetDraft(draft) {
    return "items" in draft;
}
function collectCreatedWorkflowTemplatePaths(items) {
    return items.flatMap((item) => {
        if (!usesNewTemplatePath(item)) {
            return [];
        }
        const templatePath = item.path;
        const normalizedPath = (0, types_1.normalizeWorkflowTemplatePath)(templatePath);
        return normalizedPath === templatePath ? [templatePath] : [];
    });
}
function collectCreatedWorkflowTemplateEntries(items) {
    return items.flatMap((item) => {
        if (!usesNewTemplatePath(item)) {
            return [];
        }
        const templatePath = item.path;
        const normalizedPath = (0, types_1.normalizeWorkflowTemplatePath)(templatePath);
        if (normalizedPath !== templatePath) {
            return [];
        }
        return [
            {
                path: templatePath,
                description: item.description,
                requiredSkills: item.requiredSkills,
                requiredMcp: item.requiredMcp,
                targets: item.targets,
                autoSelect: item.autoSelect,
                body: item.body,
            },
        ];
    });
}
function usesNewTemplatePath(item) {
    return (item.action === "create_new" ||
        (item.action === "update_existing" && item.path !== item.targetPath));
}
function findDuplicateTemplateDecisionPaths(items) {
    const firstIndexByPath = new Map();
    const firstUpdateIndexByTargetPath = new Map();
    const issues = [];
    for (const [index, item] of items.entries()) {
        const templatePath = item.action === "reuse_existing" ? item.targetPath : item.path;
        const normalizedPath = (0, types_1.normalizeWorkflowTemplatePath)(templatePath);
        if (normalizedPath === null || normalizedPath !== templatePath) {
            continue;
        }
        const firstIndex = firstIndexByPath.get(templatePath);
        if (firstIndex !== undefined) {
            (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
                path: [
                    "items",
                    index,
                    item.action === "reuse_existing" ? "targetPath" : "path",
                ],
                message: `template path duplicates items.${firstIndex}.`,
            });
            continue;
        }
        firstIndexByPath.set(templatePath, index);
        if (item.action !== "update_existing") {
            continue;
        }
        const targetNormalizedPath = (0, types_1.normalizeWorkflowTemplatePath)(item.targetPath);
        if (targetNormalizedPath === null ||
            targetNormalizedPath !== item.targetPath) {
            continue;
        }
        const firstTargetIndex = firstUpdateIndexByTargetPath.get(item.targetPath);
        if (firstTargetIndex !== undefined) {
            (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
                path: ["items", index, "targetPath"],
                message: `targetPath duplicates items.${firstTargetIndex}.`,
            });
            continue;
        }
        firstUpdateIndexByTargetPath.set(item.targetPath, index);
    }
    return issues;
}
function validateWorkerTemplateDraftBodyStructure(draft, input) {
    if (draft.action === "reuse_existing") {
        return [];
    }
    const effectivePath = draft.action === "create_new"
        ? (input.explicitTemplateOverrides?.path ?? draft.path)
        : draft.path;
    if ((0, types_1.isReservedWorkflowTemplateSelectorValue)(effectivePath) ||
        (0, types_1.normalizeWorkflowTemplatePath)(effectivePath) !== effectivePath) {
        return [];
    }
    return (0, template_contract_support_1.validateWorkerTemplateBodyStructure)({
        path: effectivePath,
        description: draft.action === "create_new"
            ? (input.explicitTemplateOverrides?.description ?? draft.description)
            : draft.description,
        requiredSkills: [
            ...(draft.action === "create_new"
                ? (input.explicitTemplateOverrides?.requiredSkills ??
                    draft.requiredSkills)
                : draft.requiredSkills),
        ],
        requiredMcp: [
            ...(draft.action === "create_new"
                ? (input.explicitTemplateOverrides?.requiredMcp ?? draft.requiredMcp)
                : draft.requiredMcp),
        ],
        targets: [
            ...(draft.action === "create_new"
                ? (input.explicitTemplateOverrides?.targets ?? draft.targets)
                : draft.targets),
        ],
        autoSelect: draft.action === "create_new"
            ? (input.explicitTemplateOverrides?.autoSelect ?? draft.autoSelect)
            : draft.autoSelect,
        body: draft.body,
        digest: "draft",
        existingWorkflowTemplates: [
            ...input.existingWorkflowTemplates,
            ...(input.additionalWorkflowTemplates ?? []),
        ],
        ...(draft.action === "update_existing"
            ? { replacedTemplatePath: draft.targetPath }
            : {}),
        maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
    });
}
function validateExistingTemplatePath(templatePath, path, input, issues) {
    if (!input.existingWorkflowTemplatePaths.includes(templatePath)) {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path,
            message: "targetPath must exist in the repository.",
        });
    }
}
function buildWorkerTemplateDraftExample(input) {
    const exampleContent = (0, template_contract_support_1.buildLocalizedWorkerTemplateExampleContent)(input.outputLanguage);
    const example = {
        action: "create_new",
        path: buildWorkerTemplateDraftExamplePath(input),
        description: exampleContent.description,
        requires: {
            skills: [],
            mcp: [],
        },
        targets: ["issue"],
        autoSelect: true,
        body: exampleContent.body,
    };
    return input.templateSet === true ? { items: [example] } : example;
}
function buildWorkerTemplateDraftExamplePath(input) {
    const occupiedPaths = new Set([...input.existingWorkflowTemplatePaths]);
    const candidatePaths = [
        "review/flow-change.md",
        "engineering/review-change.md",
    ];
    const availableCandidate = candidatePaths.find((candidatePath) => !occupiedPaths.has(candidatePath));
    if (availableCandidate !== undefined) {
        return availableCandidate;
    }
    for (let suffix = 1; suffix <= 100; suffix += 1) {
        const candidatePath = `workflow/draft-${suffix}.md`;
        if (!occupiedPaths.has(candidatePath)) {
            return candidatePath;
        }
    }
    return "workflow/draft.md";
}
function buildWorkerTemplateDraftRules() {
    return [
        "Return exactly one JSON object in the decision block.",
        "When template-set mode is requested, return an object with items, where each item is one create_new, update_existing, or reuse_existing decision.",
        "action is required and must be create_new, update_existing, or reuse_existing.",
        "Use create_new only when no existing workflow template should be reused or updated.",
        "Use update_existing when an existing template almost fits and should be improved instead of creating a duplicate.",
        "Use reuse_existing when an existing template already fits; do not return body for reuse_existing.",
        "If the user provided an explicit path override, use create_new and that path; do not switch to update_existing or reuse_existing.",
        "If the user provided explicit description, requires.skills, requires.mcp, targets, or autoSelect overrides, do not use reuse_existing because there is no file update where those overrides can be applied.",
        "For create_new, path, description, requires, targets, autoSelect, and body are required.",
        "For update_existing, targetPath, path, description, requires, targets, autoSelect, body, and impactSummary are required.",
        "For update_existing, targetPath is the existing template path and path is the final template path; use the same value unless template-set mode is deliberately moving the template.",
        "For update_existing outside template-set mode, path must equal targetPath.",
        "For reuse_existing, targetPath and reason are required.",
        ...template_contract_support_1.WORKER_TEMPLATE_REQUIRED_CAPABILITY_RULES,
        "Return only the selected action fields. The CLI is responsible for creating or updating workflow template files and applying explicit template overrides as the final step.",
        template_contract_support_1.WORKFLOW_TEMPLATE_SOURCE_REQUEST_RULE,
        "Abstract the concrete user prompt into a reusable work type. Workflow body must define how to perform that kind of work, not the one-off task target, requested deliverable, exact issue success criteria, or concrete repository object.",
        "Write generated human-facing text in the configured output language, including description, reason, impactSummary, Markdown body prose, document titles, and section headings. Do not translate JSON field names, enum/control values, IDs, paths, skill refs, MCP refs or tool refs, requires, skills, mcp, targets, autoSelect, @workflow selectors, commands, code, URLs, or other machine-controlled values.",
        "path must be a normalized relative .md path.",
        "targetPath must be one existing workflow template path.",
        "path must not use reserved workflow selector values such as auto, auto_select, no_template, or default.",
        "path must not contain whitespace.",
        "path must not already exist in the repository.",
        "Use normalized .md paths for workflow templates. Selectable targets belong in the top-level targets field, not in filename suffixes.",
        template_contract_support_1.WORKER_TEMPLATE_DESCRIPTION_RULE,
        template_contract_support_1.WORKER_TEMPLATE_BODY_MARKDOWN_RULE,
        "Put path and description in the top-level draft fields, not in body.",
        template_contract_support_1.WORKER_TEMPLATE_LANGUAGE_RULE,
        ...template_contract_support_1.WORKER_TEMPLATE_AUTHORING_GUIDE_RULES,
    ];
}
