"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.discoverIssueTemplates = discoverIssueTemplates;
exports.discoverPullRequestTemplates = discoverPullRequestTemplates;
exports.toWorkerDraftTemplateCandidates = toWorkerDraftTemplateCandidates;
exports.parseIssueTemplateContent = parseIssueTemplateContent;
const promises_1 = require("node:fs/promises");
const node_path_1 = __importDefault(require("node:path"));
const TEMPLATE_DIRS_BY_TRACKER_KIND = {
    github: [".github/ISSUE_TEMPLATE"],
    gitlab: [".gitlab/issue_templates"],
    gitea: [".gitea/ISSUE_TEMPLATE", ".github/ISSUE_TEMPLATE"],
};
const TEMPLATE_FILES_BY_TRACKER_KIND = {
    github: [".github/ISSUE_TEMPLATE.md"],
    gitlab: [],
    gitea: [".gitea/ISSUE_TEMPLATE.md", ".github/ISSUE_TEMPLATE.md"],
};
const PULL_REQUEST_TEMPLATE_DIRS_BY_REPOSITORY_HOST_KIND = {
    github: [
        "PULL_REQUEST_TEMPLATE",
        "docs/PULL_REQUEST_TEMPLATE",
        ".github/PULL_REQUEST_TEMPLATE",
    ],
    gitlab: [],
    gitea: [
        "PULL_REQUEST_TEMPLATE",
        "docs/PULL_REQUEST_TEMPLATE",
        ".github/PULL_REQUEST_TEMPLATE",
    ],
};
const PULL_REQUEST_TEMPLATE_FILES_BY_REPOSITORY_HOST_KIND = {
    github: [
        "pull_request_template.md",
        "PULL_REQUEST_TEMPLATE.md",
        "docs/pull_request_template.md",
        "docs/PULL_REQUEST_TEMPLATE.md",
        ".github/pull_request_template.md",
        ".github/PULL_REQUEST_TEMPLATE.md",
    ],
    gitlab: [],
    gitea: [
        "pull_request_template.md",
        "PULL_REQUEST_TEMPLATE.md",
        "docs/pull_request_template.md",
        "docs/PULL_REQUEST_TEMPLATE.md",
        ".github/pull_request_template.md",
        ".github/PULL_REQUEST_TEMPLATE.md",
    ],
};
async function discoverIssueTemplates(input) {
    return discoverMarkdownTemplates({
        repoRoot: input.repoRoot,
        templateFiles: TEMPLATE_FILES_BY_TRACKER_KIND[input.trackerKind],
        templateDirs: TEMPLATE_DIRS_BY_TRACKER_KIND[input.trackerKind],
        caseInsensitiveDedupe: false,
    });
}
async function discoverPullRequestTemplates(input) {
    return discoverMarkdownTemplates({
        repoRoot: input.repoRoot,
        templateFiles: PULL_REQUEST_TEMPLATE_FILES_BY_REPOSITORY_HOST_KIND[input.repositoryHostKind],
        templateDirs: PULL_REQUEST_TEMPLATE_DIRS_BY_REPOSITORY_HOST_KIND[input.repositoryHostKind],
        caseInsensitiveDedupe: true,
    });
}
function toWorkerDraftTemplateCandidates(templates) {
    return templates.map((template) => ({
        templatePath: template.templatePath,
        name: template.metadata.name ?? null,
        description: template.metadata.description ?? null,
        title: template.metadata.title ?? null,
        body: template.body,
    }));
}
async function discoverMarkdownTemplates(input) {
    const templatePaths = await collectCandidateTemplatePaths(input);
    const templates = [];
    for (const templatePath of templatePaths) {
        const template = await readTemplate(input.repoRoot, templatePath);
        if (template === null) {
            continue;
        }
        templates.push({ templatePath, ...template });
    }
    return templates;
}
async function collectCandidateTemplatePaths(input) {
    const templatePaths = [];
    for (const templatePath of input.templateFiles) {
        templatePaths.push(templatePath);
    }
    for (const templateDir of input.templateDirs) {
        const entries = await readDirectoryEntries(input.repoRoot, templateDir);
        for (const entry of entries) {
            if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".md")) {
                continue;
            }
            templatePaths.push(node_path_1.default.posix.join(templateDir, entry.name));
        }
    }
    const normalizedSeen = new Set();
    const uniquePaths = [];
    for (const templatePath of templatePaths) {
        const normalizedKey = input.caseInsensitiveDedupe
            ? templatePath.toLowerCase()
            : templatePath;
        if (normalizedSeen.has(normalizedKey)) {
            continue;
        }
        normalizedSeen.add(normalizedKey);
        uniquePaths.push(templatePath);
    }
    return uniquePaths;
}
async function readDirectoryEntries(repoRoot, templateDir) {
    try {
        const entries = await (0, promises_1.readdir)(node_path_1.default.join(repoRoot, templateDir), {
            withFileTypes: true,
        });
        return entries.sort((left, right) => left.name.localeCompare(right.name));
    }
    catch (error) {
        if (isExpectedMissingTemplateError(error)) {
            return [];
        }
        throw error;
    }
}
async function readTemplate(repoRoot, templatePath) {
    const filePath = node_path_1.default.join(repoRoot, templatePath);
    try {
        const content = await (0, promises_1.readFile)(filePath, "utf8");
        if (content.trim() === "") {
            return null;
        }
        const parsed = parseIssueTemplateContent(content);
        if (parsed.body.trim() === "") {
            return null;
        }
        return parsed;
    }
    catch (error) {
        if (isExpectedMissingTemplateError(error)) {
            return null;
        }
        throw error;
    }
}
function isExpectedMissingTemplateError(error) {
    return (error instanceof Error &&
        "code" in error &&
        (error.code === "ENOENT" ||
            error.code === "ENOTDIR" ||
            error.code === "EISDIR"));
}
function parseIssueTemplateContent(content) {
    const normalized = content.replace(/\r\n?/g, "\n");
    const lines = normalized.split("\n");
    if (lines[0] !== "---") {
        return { metadata: {}, body: content };
    }
    const endIndex = lines.indexOf("---", 1);
    if (endIndex === -1) {
        return { metadata: {}, body: content };
    }
    const metadata = parseIssueTemplateFrontmatter(lines.slice(1, endIndex));
    if (metadata === null) {
        return { metadata: {}, body: content };
    }
    return {
        metadata,
        body: lines.slice(endIndex + 1).join("\n"),
    };
}
function parseIssueTemplateFrontmatter(lines) {
    const metadata = {};
    for (const line of lines) {
        const trimmed = line.trim();
        if (trimmed === "" || trimmed.startsWith("#")) {
            continue;
        }
        const match = /^([A-Za-z][A-Za-z0-9_-]*):(?:\s*(.*))?$/.exec(line);
        if (match === null) {
            return null;
        }
        const value = parseScalarString(match[2] ?? "");
        if (value === null) {
            return null;
        }
        switch (match[1]) {
            case "name":
                metadata.name = value;
                break;
            case "about":
            case "description":
                metadata.description = value;
                break;
            case "title":
                metadata.title = value;
                break;
        }
    }
    return metadata;
}
function parseScalarString(value) {
    const trimmed = value.trim();
    if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
        return null;
    }
    if (trimmed === "|" || trimmed === ">") {
        return null;
    }
    if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
        (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
        return trimmed.slice(1, -1);
    }
    if (trimmed.startsWith('"') || trimmed.startsWith("'")) {
        return null;
    }
    return trimmed;
}
