"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runIgnoreRecommendationCheck = runIgnoreRecommendationCheck;
exports.runMarkdownlintRecommendationCheck = runMarkdownlintRecommendationCheck;
exports.runSandboxParentPathIdentityCheck = runSandboxParentPathIdentityCheck;
exports.runSandboxPathHygieneCheck = runSandboxPathHygieneCheck;
exports.runSandboxCleanupReadinessCheck = runSandboxCleanupReadinessCheck;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const workspace_ignore_1 = require("../workspace-ignore");
const default_assets_1 = require("../workspace-init/default-assets");
const sandbox_contract_1 = require("../paths/sandbox-contract");
const local_paths_1 = require("./local-paths");
function runIgnoreRecommendationCheck(repositoryRoot, findings) {
    const preview = (0, workspace_ignore_1.createIgnoreInstallPreview)(repositoryRoot);
    if (preview.proposedAdditions.length > 0) {
        findings.push({
            code: "IGNORE_RULES_RECOMMENDED",
            message: `Recommended local ignore entries are missing (${preview.proposedAdditions.join(", ")}); run 'day-shift ignore install'.`,
            severity: "warning",
            path: ".gitignore"
        });
        return {
            id: "ignore-rules-recommendation",
            status: "warning",
            message: "Recommended local ignore entries are missing."
        };
    }
    return {
        id: "ignore-rules-recommendation",
        status: "ok",
        message: "Recommended local ignore entries are installed."
    };
}
function runMarkdownlintRecommendationCheck(repositoryRoot, findings) {
    const markdownlintRelativePath = ".markdownlint.json";
    const markdownlintPath = node_path_1.default.join(repositoryRoot, markdownlintRelativePath);
    if (!(0, local_paths_1.isExistingFile)(markdownlintPath)) {
        findings.push({
            code: "MARKDOWNLINT_RECOMMENDED",
            message: "Root .markdownlint.json is missing; run 'day-shift init' to scaffold the recommended Markdown lint config.",
            severity: "warning",
            path: markdownlintRelativePath
        });
        return {
            id: "markdownlint-recommendation",
            status: "warning",
            message: "Recommended root .markdownlint.json is missing."
        };
    }
    try {
        const parsed = JSON.parse(node_fs_1.default.readFileSync(markdownlintPath, "utf8"));
        const isCompatible = parsed.MD025 !== undefined
            && typeof parsed.MD025 === "object"
            && parsed.MD025 !== null
            && parsed.MD025.front_matter_title === default_assets_1.RECOMMENDED_MARKDOWNLINT_CONTENTS.MD025.front_matter_title;
        if (!isCompatible) {
            findings.push({
                code: "MARKDOWNLINT_INCOMPATIBLE",
                message: `Root .markdownlint.json is present but incompatible with Day Shift Markdown conventions (expected MD025.front_matter_title = ${JSON.stringify(default_assets_1.RECOMMENDED_MARKDOWNLINT_CONTENTS.MD025.front_matter_title)}).`,
                severity: "warning",
                path: markdownlintRelativePath
            });
            return {
                id: "markdownlint-recommendation",
                status: "warning",
                message: "Root .markdownlint.json is incompatible with Day Shift conventions."
            };
        }
        return {
            id: "markdownlint-recommendation",
            status: "ok",
            message: "Root .markdownlint.json is present and compatible."
        };
    }
    catch {
        findings.push({
            code: "MARKDOWNLINT_INCOMPATIBLE",
            message: "Root .markdownlint.json is unreadable or invalid JSON.",
            severity: "warning",
            path: markdownlintRelativePath
        });
        return {
            id: "markdownlint-recommendation",
            status: "warning",
            message: "Root .markdownlint.json could not be parsed."
        };
    }
}
function runSandboxParentPathIdentityCheck(repositoryRoot, findings) {
    const sandboxParentPath = node_path_1.default.join(repositoryRoot, sandbox_contract_1.SANDBOX_PARENT_DIRECTORY);
    if (!node_fs_1.default.existsSync(sandboxParentPath)) {
        return {
            check: {
                id: "sandbox-parent-path-identity",
                status: "ok",
                message: "Sandbox parent path is not present yet; no disposable sandbox runs were detected."
            },
            sandboxParentPath: null
        };
    }
    let parentStat;
    try {
        parentStat = node_fs_1.default.lstatSync(sandboxParentPath);
    }
    catch {
        findings.push({
            code: "SANDBOX_PARENT_PATH_UNREADABLE",
            message: "Sandbox parent path exists but could not be inspected.",
            severity: "error",
            path: sandbox_contract_1.SANDBOX_PARENT_DIRECTORY
        });
        return {
            check: {
                id: "sandbox-parent-path-identity",
                status: "error",
                message: "Sandbox parent path could not be inspected."
            },
            sandboxParentPath: null
        };
    }
    if (parentStat.isSymbolicLink()) {
        findings.push({
            code: "SANDBOX_PARENT_PATH_INVALID",
            message: "Sandbox parent path must be a repository-local directory and must not be a symbolic link.",
            severity: "error",
            path: sandbox_contract_1.SANDBOX_PARENT_DIRECTORY
        });
        return {
            check: {
                id: "sandbox-parent-path-identity",
                status: "error",
                message: "Sandbox parent path is a symbolic link."
            },
            sandboxParentPath: null
        };
    }
    if (!parentStat.isDirectory()) {
        findings.push({
            code: "SANDBOX_PARENT_PATH_INVALID",
            message: "Sandbox parent path must be a directory.",
            severity: "error",
            path: sandbox_contract_1.SANDBOX_PARENT_DIRECTORY
        });
        return {
            check: {
                id: "sandbox-parent-path-identity",
                status: "error",
                message: "Sandbox parent path is not a directory."
            },
            sandboxParentPath: null
        };
    }
    try {
        const resolvedSandboxParentPath = node_fs_1.default.realpathSync(sandboxParentPath);
        if (!isWithinRepositoryRoot(repositoryRoot, resolvedSandboxParentPath)) {
            findings.push({
                code: "SANDBOX_PARENT_PATH_INVALID",
                message: "Sandbox parent path resolves outside the repository root.",
                severity: "error",
                path: sandbox_contract_1.SANDBOX_PARENT_DIRECTORY
            });
            return {
                check: {
                    id: "sandbox-parent-path-identity",
                    status: "error",
                    message: "Sandbox parent path resolves outside the repository root."
                },
                sandboxParentPath: null
            };
        }
    }
    catch {
        findings.push({
            code: "SANDBOX_PARENT_PATH_UNREADABLE",
            message: "Sandbox parent path exists but could not be resolved.",
            severity: "error",
            path: sandbox_contract_1.SANDBOX_PARENT_DIRECTORY
        });
        return {
            check: {
                id: "sandbox-parent-path-identity",
                status: "error",
                message: "Sandbox parent path could not be resolved."
            },
            sandboxParentPath: null
        };
    }
    return {
        check: {
            id: "sandbox-parent-path-identity",
            status: "ok",
            message: "Sandbox parent path resolves to a repository-local directory."
        },
        sandboxParentPath
    };
}
function runSandboxPathHygieneCheck(sandboxParentPath, findings) {
    if (sandboxParentPath === null) {
        return {
            id: "sandbox-path-hygiene",
            status: "ok",
            message: "Sandbox path hygiene is healthy; no sandbox parent path is present."
        };
    }
    const sandboxEntries = node_fs_1.default.readdirSync(sandboxParentPath, { withFileTypes: true });
    let hasHygieneViolation = false;
    for (const entry of sandboxEntries) {
        const entryRelativePath = node_path_1.default.posix.join(sandbox_contract_1.SANDBOX_PARENT_DIRECTORY, entry.name);
        const entryAbsolutePath = node_path_1.default.join(sandboxParentPath, entry.name);
        if (!entry.isDirectory()) {
            hasHygieneViolation = true;
            findings.push({
                code: "SANDBOX_HYGIENE_NON_DIRECTORY_ENTRY",
                message: "Sandbox parent contains a non-directory entry; sandbox/ should only contain run directories.",
                severity: "error",
                path: entryRelativePath
            });
            continue;
        }
        if (!(0, sandbox_contract_1.isSandboxRunDirectoryName)(entry.name)) {
            hasHygieneViolation = true;
            findings.push({
                code: "SANDBOX_HYGIENE_UNEXPECTED_SIBLING_ROOT",
                message: "Sandbox parent contains an unexpected directory; expected only run-<run-id> directories.",
                severity: "error",
                path: entryRelativePath
            });
            continue;
        }
        if (isNestedPlanningRootPresent(entryAbsolutePath)) {
            hasHygieneViolation = true;
            findings.push({
                code: "SANDBOX_HYGIENE_NESTED_PLANNING_ROOT",
                message: "Sandbox run directory contains a nested .day-shift/planning root, which violates sandbox hygiene boundaries.",
                severity: "error",
                path: entryRelativePath
            });
        }
    }
    if (hasHygieneViolation) {
        return {
            id: "sandbox-path-hygiene",
            status: "error",
            message: "Sandbox path hygiene violations were detected."
        };
    }
    return {
        id: "sandbox-path-hygiene",
        status: "ok",
        message: "Sandbox entries satisfy v1 path hygiene rules."
    };
}
function runSandboxCleanupReadinessCheck(repositoryRoot, sandboxParentPath, findings) {
    if (sandboxParentPath === null) {
        return {
            id: "sandbox-cleanup-readiness",
            status: "ok",
            message: "No sandbox runs were detected for cleanup guidance."
        };
    }
    const sandboxEntries = node_fs_1.default.readdirSync(sandboxParentPath, { withFileTypes: true });
    let staleRunCount = 0;
    for (const entry of sandboxEntries) {
        if (!entry.isDirectory() || !(0, sandbox_contract_1.isSandboxRunDirectoryName)(entry.name)) {
            continue;
        }
        const runAbsolutePath = node_path_1.default.join(sandboxParentPath, entry.name);
        const runRelativePath = (0, local_paths_1.toRepositoryRelativePath)(repositoryRoot, runAbsolutePath);
        const runEntries = node_fs_1.default.readdirSync(runAbsolutePath, { withFileTypes: true });
        if (runEntries.length === 0) {
            staleRunCount += 1;
            findings.push({
                code: "SANDBOX_STALE_RUN_CLEANUP_RECOMMENDED",
                message: "Empty sandbox run directory appears stale and can be cleaned up manually if no longer needed.",
                severity: "informational",
                path: runRelativePath
            });
        }
    }
    if (staleRunCount > 0) {
        return {
            id: "sandbox-cleanup-readiness",
            status: "informational",
            message: `Found ${staleRunCount} empty sandbox run director${staleRunCount === 1 ? "y" : "ies"} that may be safe to clean up.`
        };
    }
    return {
        id: "sandbox-cleanup-readiness",
        status: "ok",
        message: "No empty sandbox run directories were detected."
    };
}
function isNestedPlanningRootPresent(runDirectoryPath) {
    const nestedPlanningRootPath = node_path_1.default.join(runDirectoryPath, ".day-shift", "planning");
    return (0, local_paths_1.isExistingDirectory)(nestedPlanningRootPath);
}
function isWithinRepositoryRoot(repositoryRoot, absolutePath) {
    const relativePath = node_path_1.default.relative(repositoryRoot, absolutePath);
    return relativePath === "" || (!relativePath.startsWith("..") && !node_path_1.default.isAbsolute(relativePath));
}
