"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.REPOSITORY_SIZE_WARNING_THRESHOLD_BYTES = exports.checkWorkflowTemplates = void 0;
exports.checkRepoRegistration = checkRepoRegistration;
exports.checkRemoteBaseBranch = checkRemoteBaseBranch;
exports.checkRepositoryHostAccess = checkRepositoryHostAccess;
exports.checkIssueCompletion = checkIssueCompletion;
exports.checkDependenciesStrategy = checkDependenciesStrategy;
exports.checkTrackerSchema = checkTrackerSchema;
exports.checkWorkspaceRoot = checkWorkspaceRoot;
exports.checkRepositorySize = checkRepositorySize;
const node_path_1 = __importDefault(require("node:path"));
const promises_1 = require("node:fs/promises");
const tracked_project_1 = require("../../core/tracked-project");
const provider_resolution_1 = require("../../platform/provider-resolution");
const repo_registry_1 = require("../../core/repo-registry");
const factory_1 = require("../../platform/ticket-tracker/factory");
const default_issue_workspace_manager_1 = require("../../workspaces/default-issue-workspace-manager");
const remote_base_branch_1 = require("../../git/remote-base-branch");
const catalog_1 = require("../../i18n/catalog");
const check_names_1 = require("./check-names");
var template_health_1 = require("../../workflows/template-health");
Object.defineProperty(exports, "checkWorkflowTemplates", { enumerable: true, get: function () { return template_health_1.checkWorkflowTemplates; } });
exports.REPOSITORY_SIZE_WARNING_THRESHOLD_BYTES = 5 * 1024 * 1024 * 1024;
async function checkRepoRegistration(cwd, config, locale = catalog_1.DEFAULT_APP_LOCALE) {
    try {
        const registry = await (0, repo_registry_1.loadRepoRegistry)(undefined, locale);
        const trackedProjectKey = (0, provider_resolution_1.getTrackedProjectKey)((0, tracked_project_1.toTrackedProjectRef)(config));
        const entry = registry.repos.find((candidate) => (0, provider_resolution_1.getTrackedProjectKey)((0, tracked_project_1.toTrackedProjectRef)(candidate)) ===
            trackedProjectKey);
        if (!entry) {
            return {
                name: (0, check_names_1.getDoctorCheckName)("registry", locale),
                status: "warning",
                message: (0, catalog_1.translate)(locale, "doctor.repo.registry.missing"),
            };
        }
        if (node_path_1.default.resolve(entry.cwd) !== node_path_1.default.resolve(cwd)) {
            return {
                name: (0, check_names_1.getDoctorCheckName)("registry", locale),
                status: "fail",
                message: (0, catalog_1.translate)(locale, "doctor.repo.registry.differentCwd", {
                    cwd: entry.cwd,
                    currentCwd: node_path_1.default.resolve(cwd),
                }),
            };
        }
        return {
            name: (0, check_names_1.getDoctorCheckName)("registry", locale),
            status: "ok",
            message: (0, catalog_1.translate)(locale, "doctor.repo.registry.present", {
                cwd: node_path_1.default.resolve(cwd),
                currentCwd: node_path_1.default.resolve(cwd),
            }),
        };
    }
    catch (error) {
        return {
            name: (0, check_names_1.getDoctorCheckName)("registry", locale),
            status: "warning",
            message: error instanceof Error
                ? error.message
                : (0, catalog_1.translate)(locale, "doctor.repo.registry.readFailed"),
        };
    }
}
async function checkRemoteBaseBranch(cwd, config, locale = catalog_1.DEFAULT_APP_LOCALE, authProvider) {
    const remoteName = config.repositoryHost.remoteName;
    const baseBranch = config.repositoryHost.baseBranch;
    try {
        const result = await (0, remote_base_branch_1.checkRemoteBaseBranchRef)({
            cwd,
            locale,
            remoteName,
            baseBranch,
            projectRef: config.repositoryHost.projectRef,
            ...(authProvider !== undefined
                ? {
                    credentials: await (0, remote_base_branch_1.tryResolveRemoteBaseBranchGitCredentials)(authProvider, config.repositoryHost),
                }
                : {}),
        });
        if (result.kind === "check_failed") {
            return {
                name: (0, check_names_1.getDoctorCheckName)("remoteBaseBranch", locale),
                status: "fail",
                message: result.message,
            };
        }
        if (result.kind === "missing") {
            return {
                name: (0, check_names_1.getDoctorCheckName)("remoteBaseBranch", locale),
                status: "fail",
                message: result.message,
            };
        }
        return {
            name: (0, check_names_1.getDoctorCheckName)("remoteBaseBranch", locale),
            status: "ok",
            message: (0, catalog_1.translate)(locale, "doctor.repo.remoteBaseBranch.present", {
                remoteName,
                baseBranch,
                cwd: node_path_1.default.resolve(cwd),
            }),
        };
    }
    catch (error) {
        return {
            name: (0, check_names_1.getDoctorCheckName)("remoteBaseBranch", locale),
            status: "fail",
            message: (0, catalog_1.translate)(locale, "doctor.repo.remoteBaseBranch.checkFailed", {
                remoteName,
                baseBranch,
                cwd: node_path_1.default.resolve(cwd),
                message: error instanceof Error ? error.message : String(error),
            }),
        };
    }
}
async function checkRepositoryHostAccess(repositoryHost, locale = catalog_1.DEFAULT_APP_LOCALE) {
    try {
        const repository = await repositoryHost.getRepository();
        return {
            name: (0, check_names_1.getDoctorCheckName)("repositoryHostAccess", locale),
            status: "ok",
            message: (0, catalog_1.translate)(locale, "doctor.repo.repositoryHostAccess.reachable", {
                defaultBranch: repository.defaultBranch,
            }),
        };
    }
    catch (error) {
        return {
            name: (0, check_names_1.getDoctorCheckName)("repositoryHostAccess", locale),
            status: "fail",
            message: error instanceof Error
                ? error.message
                : (0, catalog_1.translate)(locale, "doctor.repo.repositoryHostAccess.unreachable"),
        };
    }
}
function checkIssueCompletion(config, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return {
        name: (0, check_names_1.getDoctorCheckName)("issueCompletion", locale),
        status: "ok",
        message: (0, catalog_1.translate)(locale, "doctor.repo.issueCompletion", {
            target: config.issueCompletion.target,
            reviewPolicy: config.issueCompletion.pullRequest.reviewPolicy,
            mergePolicy: config.issueCompletion.pullRequest.mergePolicy,
        }),
    };
}
function checkDependenciesStrategy(config, locale = catalog_1.DEFAULT_APP_LOCALE) {
    return {
        name: (0, check_names_1.getDoctorCheckName)("dependenciesStrategy", locale),
        status: "ok",
        message: (0, catalog_1.translate)(locale, `doctor.repo.dependenciesStrategy.${config.dependencies.strategy}`),
    };
}
async function checkTrackerSchema(config, authProvider, locale = catalog_1.DEFAULT_APP_LOCALE) {
    try {
        const result = await (0, factory_1.checkTicketTrackerWorkflowSchema)(config, authProvider);
        if (!result.ok) {
            return {
                name: (0, check_names_1.getDoctorCheckName)("trackerSchema", locale),
                status: "warning",
                message: (0, catalog_1.translate)(locale, "doctor.repo.trackerSchema.missing", {
                    labels: result.missingRequirements
                        .map((requirement) => requirement.name)
                        .join(", "),
                }),
            };
        }
        return {
            name: (0, check_names_1.getDoctorCheckName)("trackerSchema", locale),
            status: "ok",
            message: (0, catalog_1.translate)(locale, "doctor.repo.trackerSchema.available"),
        };
    }
    catch {
        return {
            name: (0, check_names_1.getDoctorCheckName)("trackerSchema", locale),
            status: "warning",
            message: (0, catalog_1.translate)(locale, "doctor.repo.trackerSchema.unknown"),
        };
    }
}
async function checkWorkspaceRoot(config, locale = catalog_1.DEFAULT_APP_LOCALE) {
    const workspacePath = (0, default_issue_workspace_manager_1.getIssueWorkspacePath)((0, tracked_project_1.toTrackedProjectRef)(config), "1");
    const parentDirectory = node_path_1.default.dirname(workspacePath);
    try {
        await (0, promises_1.mkdir)(parentDirectory, { recursive: true });
        return {
            name: (0, check_names_1.getDoctorCheckName)("workspaceRoot", locale),
            status: "ok",
            message: (0, catalog_1.translate)(locale, "doctor.repo.workspaceRoot.writable", {
                path: parentDirectory,
            }),
        };
    }
    catch {
        return {
            name: (0, check_names_1.getDoctorCheckName)("workspaceRoot", locale),
            status: "fail",
            message: (0, catalog_1.translate)(locale, "doctor.repo.workspaceRoot.notWritable", {
                path: parentDirectory,
            }),
        };
    }
}
async function checkRepositorySize(cwd, locale = catalog_1.DEFAULT_APP_LOCALE, options = {}) {
    const thresholdBytes = options.warningThresholdBytes ?? exports.REPOSITORY_SIZE_WARNING_THRESHOLD_BYTES;
    try {
        const sizeBytes = await measureDirectorySize(cwd);
        if (sizeBytes < thresholdBytes) {
            return null;
        }
        return {
            name: (0, check_names_1.getDoctorCheckName)("repositorySize", locale),
            status: "warning",
            message: (0, catalog_1.translate)(locale, "doctor.repo.repositorySize.large", {
                size: formatByteSize(sizeBytes),
            }),
        };
    }
    catch {
        return null;
    }
}
async function measureDirectorySize(targetPath) {
    const stat = await (0, promises_1.lstat)(targetPath);
    if (stat.isSymbolicLink()) {
        return stat.size;
    }
    if (!stat.isDirectory()) {
        return stat.isFile() ? stat.size : 0;
    }
    let totalBytes = 0;
    const directory = await (0, promises_1.opendir)(targetPath);
    for await (const entry of directory) {
        totalBytes += await measureDirectorySize(node_path_1.default.join(targetPath, entry.name));
    }
    return totalBytes;
}
function formatByteSize(bytes) {
    const units = ["B", "KB", "MB", "GB", "TB"];
    let value = bytes;
    let unitIndex = 0;
    while (value >= 1024 && unitIndex < units.length - 1) {
        value /= 1024;
        unitIndex += 1;
    }
    if (unitIndex === 0) {
        return `${bytes}B`;
    }
    const formatted = value >= 10 ? Math.round(value).toString() : value.toFixed(1);
    return `${formatted}${units[unitIndex]}`;
}
