"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildWorkerIssueDraftContract = buildWorkerIssueDraftContract;
exports.validateWorkerIssueDraftSemanticRules = validateWorkerIssueDraftSemanticRules;
const node_path_1 = __importDefault(require("node:path"));
const zod_1 = require("zod");
const branding_1 = require("../core/branding");
const comment_command_1 = require("../workflows/comment-command");
const structured_contract_support_1 = require("./structured-contract-support");
const validation_issues_1 = require("./validation-issues");
const workerIssueDraftSchema = zod_1.z
    .object({
    title: zod_1.z
        .string()
        .min(1)
        .max(180)
        .describe("Concise draft title in the configured output language."),
    body: zod_1.z
        .string()
        .min(1)
        .describe(`Human-facing Markdown body in the configured output language. Do not include workflow metadata or tracker metadata, and do not start with executable ${branding_1.ISSUE_COMMENT_COMMAND_PREFIX} commands.`),
    selectedIssueTemplatePath: zod_1.z
        .string()
        .min(1)
        .nullable()
        .optional()
        .describe("Repository template path used to shape the body, or null when no listed template matches. This is an audit record, not a request to re-apply a provider template."),
})
    .strict()
    .describe("Draft.");
function buildWorkerIssueDraftContract(input) {
    return (0, structured_contract_support_1.buildWorkerStructuredContract)({
        schema: workerIssueDraftSchema,
        example: buildWorkerIssueDraftExample(input),
        rules: buildWorkerIssueDraftRules(input),
    });
}
function validateWorkerIssueDraftSemanticRules(draft, input) {
    const issues = [];
    if ((0, comment_command_1.hasIssueCommentCommandOnFirstNonEmptyLine)(draft.title)) {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path: ["title"],
            message: `title must not start with ${branding_1.ISSUE_COMMENT_COMMAND_PREFIX} workflow commands.`,
        });
    }
    if ((0, comment_command_1.hasIssueCommentCommandOnFirstNonEmptyLine)(draft.body)) {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path: ["body"],
            message: `body must not start with ${branding_1.ISSUE_COMMENT_COMMAND_PREFIX} workflow commands.`,
        });
    }
    validateIssueBodyMetadataLines(draft.body, issues);
    validateIssueBodyWorkflowProcessHeadings(draft, input, issues);
    validateIssueTemplatePath(draft.selectedIssueTemplatePath ?? null, input, ["selectedIssueTemplatePath"], issues);
    validateSelectedIssueTemplateBody(draft, input, issues);
    return issues;
}
function validateIssueBodyWorkflowProcessHeadings(draft, input, issues) {
    if (!extractMarkdownHeadings(draft.body).includes("required process")) {
        return;
    }
    const selectedTemplate = (input.availableIssueTemplates ?? []).find((entry) => entry.templatePath === (draft.selectedIssueTemplatePath ?? null));
    if (selectedTemplate !== undefined &&
        extractMarkdownHeadings(selectedTemplate.body).includes("required process")) {
        return;
    }
    (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
        path: ["body"],
        message: "body must not include reusable workflow/process sections such as ## Required Process; put reusable process guidance in workflow templates instead.",
    });
}
function validateIssueBodyMetadataLines(body, issues) {
    const metadataLine = body
        .split("\n")
        .find((line) => isIssueBodyMetadataLine(line));
    if (metadataLine === undefined) {
        return;
    }
    (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
        path: ["body"],
        message: `body must not include workflow or tracker metadata lines such as "${metadataLine.trim()}"; put metadata in draft fields instead.`,
    });
}
function isIssueBodyMetadataLine(line) {
    const normalized = line.trim().replace(/^[-*]\s+/u, "");
    return (/^(workflow metadata|tracker metadata|workflow|schedule|labels|assignees|milestone|project)\s*:/iu.test(normalized) ||
        /^#{1,6}\s+(workflow metadata|tracker metadata|workflow|schedule|labels|assignees|milestone|project)\s*$/iu.test(normalized));
}
function validateSelectedIssueTemplateBody(draft, input, issues) {
    const templatePath = draft.selectedIssueTemplatePath ?? null;
    if (templatePath === null) {
        return;
    }
    const candidate = (input.availableIssueTemplates ?? []).find((entry) => entry.templatePath === templatePath);
    if (candidate === undefined) {
        return;
    }
    const expectedHeadings = extractMarkdownHeadings(candidate.body);
    if (expectedHeadings.length === 0) {
        return;
    }
    const bodyHeadings = extractMarkdownHeadings(draft.body);
    let bodyCursor = 0;
    for (const expected of expectedHeadings) {
        const foundIndex = bodyHeadings.indexOf(expected, bodyCursor);
        if (foundIndex === -1) {
            (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
                path: ["body"],
                message: `body must preserve the selected ${formatTemplateKind(input)} template headings and their order.`,
            });
            return;
        }
        bodyCursor = foundIndex + 1;
    }
}
function extractMarkdownHeadings(markdown) {
    return markdown.split("\n").flatMap((line) => {
        const match = line.match(/^#{1,6}\s+(.+?)\s*#*\s*$/u);
        return match?.[1] === undefined ? [] : [normalizeHeading(match[1])];
    });
}
function normalizeHeading(heading) {
    return heading.trim().replace(/\s+/gu, " ").toLowerCase();
}
function validateIssueTemplatePath(templatePath, input, issuePath, issues) {
    if (templatePath === null) {
        return;
    }
    if (normalizeIssueTemplatePath(templatePath) !== templatePath) {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path: issuePath,
            message: "selectedIssueTemplatePath must be a normalized relative path.",
        });
        return;
    }
    const candidatePaths = new Set((input.availableIssueTemplates ?? []).map((candidate) => candidate.templatePath));
    if (!candidatePaths.has(templatePath)) {
        (0, validation_issues_1.addWorkerSemanticValidationIssue)(issues, {
            path: issuePath,
            message: `selectedIssueTemplatePath must exist in the provided ${formatTemplateKind(input)} template candidates.`,
        });
    }
}
function formatTemplateKind(input) {
    return input.templateKind === "pull_request" ? "pull request" : "issue";
}
function normalizeIssueTemplatePath(selector) {
    const trimmed = selector.trim();
    if (trimmed.length === 0 ||
        trimmed.includes("\\") ||
        node_path_1.default.isAbsolute(trimmed) ||
        /\s/u.test(trimmed)) {
        return null;
    }
    const normalized = node_path_1.default.posix.normalize(trimmed);
    if (normalized.length === 0 ||
        normalized === "." ||
        normalized !== trimmed ||
        normalized.startsWith("../") ||
        normalized.includes("/../") ||
        normalized.split("/").some((segment) => {
            return segment === "." || segment === ".." || segment.length === 0;
        })) {
        return null;
    }
    return normalized;
}
function buildWorkerIssueDraftExample(input) {
    const firstIssueTemplate = input.availableIssueTemplates?.[0] ?? null;
    const text = buildWorkerIssueDraftExampleText(input);
    return {
        title: text.title,
        body: text.body,
        selectedIssueTemplatePath: firstIssueTemplate?.templatePath ?? null,
    };
}
function buildWorkerIssueDraftExampleText(input) {
    if (input.templateKind === "pull_request") {
        return buildWorkerPullRequestDraftExampleText(input.outputLanguage);
    }
    return buildWorkerTrackerIssueDraftExampleText(input.outputLanguage);
}
function buildWorkerTrackerIssueDraftExampleText(locale) {
    switch (locale) {
        case "ja":
            return {
                title: "独立したブロッカーを調査する",
                body: [
                    "親作業とは別に、独立したブロッカーを追跡する。",
                    "",
                    "対応可能な場合はブロッカーを解消する。対応できない場合は、必要な判断またはアクセスを具体的に示して人に引き継ぐ。",
                ].join("\n"),
            };
        case "zh":
            return {
                title: "调查独立阻塞项",
                body: [
                    "将独立阻塞项与父级工作分开跟踪。",
                    "",
                    "如果阻塞项可处理，则解决它；如果不可处理，则说明缺少的具体决策或访问权限并移交给人工。",
                ].join("\n"),
            };
        case "en":
            return {
                title: "Investigate independent blocker",
                body: [
                    "Track the independent blocker separately from the parent work.",
                    "",
                    "Resolve the blocker if it is actionable. If it is not actionable, hand it back with the specific missing decision or access needed.",
                ].join("\n"),
            };
    }
}
function buildWorkerPullRequestDraftExampleText(locale) {
    switch (locale) {
        case "ja":
            return {
                title: "publish の変更内容",
                body: ["## Summary", "", "publish の変更内容をまとめる。"].join("\n"),
            };
        case "zh":
            return {
                title: "publish 变更内容",
                body: ["## Summary", "", "总结 publish 的变更内容。"].join("\n"),
            };
        case "en":
            return {
                title: "Publish changes",
                body: ["## Summary", "", "Summarize the publish changes."].join("\n"),
            };
    }
}
function buildWorkerIssueDraftRules(input) {
    const templateNoun = input.templateKind === "pull_request"
        ? "pull request template"
        : "issue template";
    const templateNounPlural = input.templateKind === "pull_request"
        ? "pull request templates"
        : "issue templates";
    const rules = [
        "Return exactly one JSON object in the decision block.",
        "Return only title, body, and selectedIssueTemplatePath.",
        "title and body are required; title must be 1-180 characters.",
        `Write generated human-facing text in the configured output language. Do not translate workflow metadata, ${templateNoun} paths, commands, enum/control values, or other machine-controlled values.`,
        `title and body must not start with executable ${branding_1.ISSUE_COMMENT_COMMAND_PREFIX} workflow commands; ordinary URLs, paths, or explanatory references containing "alpaca" are allowed when relevant.`,
        "When the source request is abstract, body must make the inferred primary outcome, expected deliverable quality, observable success evidence, constraints, and unknowns clear without forcing 5W1H headings unless the selected issue template asks for them.",
        "For abstract improvement or optimization requests, body must distinguish the desired direction from measurable success: improvement target, current state or baseline to inspect, metric or evaluation axis, source of truth, measurement window when relevant, target or decision threshold when provided, guardrails or non-goals that prevent proxy success, and unknowns. Do not invent numeric targets when the user did not provide them.",
        "Do not turn body into reusable how-to workflow/process guidance; reusable investigation, development, verification, or operation rules belong in workflow templates.",
        "Do not put workflow metadata, schedule, labels, assignees, milestone, project, or tracker-only metadata in body.",
        `selectedIssueTemplatePath is optional; use one available ${templateNoun} path when there is a clear match, otherwise use null or omit it.`,
        `selectedIssueTemplatePath records the repository ${templateNoun} used to shape body; it is not a request to re-apply that provider template during publish.`,
        `Repository ${templateNounPlural} are separate from AlpacaLoop workflow templates and only shape the drafted body.`,
        `When selectedIssueTemplatePath is non-null, preserve that ${templateNoun}'s questions, order, and headings in body.`,
        `Do not invent facts for unknown ${templateNoun} fields.`,
    ];
    appendIssueTemplateCandidateRule(rules, input.availableIssueTemplates ?? [], templateNoun);
    return rules;
}
function appendIssueTemplateCandidateRule(rules, candidates, templateNoun) {
    if (candidates.length === 0) {
        rules.push(`selectedIssueTemplatePath must be null or omitted because no ${templateNoun}s were provided.`);
        return;
    }
    rules.push(`selectedIssueTemplatePath must be one of: ${candidates.map((candidate) => candidate.templatePath).join(", ")}; or null when none match.`);
}
