"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TRACKABLE_DAY_SHIFT_SHARED_ASSET_PATHS = exports.CANONICAL_DAY_SHIFT_LOCAL_IGNORE_RULES = exports.IGNORE_POLICY_VERSION = void 0;
exports.parseIgnoreFileRules = parseIgnoreFileRules;
exports.createIgnorePolicy = createIgnorePolicy;
exports.normalizeWorkspaceRelativePath = normalizeWorkspaceRelativePath;
exports.explainIgnorePolicy = explainIgnorePolicy;
exports.getCanonicalDayShiftLocalIgnoreEntries = getCanonicalDayShiftLocalIgnoreEntries;
exports.renderCanonicalIgnoreInstallContractText = renderCanonicalIgnoreInstallContractText;
exports.createIgnoreInstallPreview = createIgnoreInstallPreview;
exports.applyIgnoreInstallPreview = applyIgnoreInstallPreview;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const preview_normalization_1 = require("./preview-normalization");
__exportStar(require("./integration-adapters"), exports);
exports.IGNORE_POLICY_VERSION = "1";
const DEFAULT_SCAN_RULES = [
    ...["node_modules/", "dist/", "build/", "coverage/", ".cache/", ".turbo/", ".next/", "sandbox/", "tmp/"].map((pattern) => ({
        pattern,
        decision: "exclude",
        rationale: "Safe default excludes dependency, generated, cache, test-output, or disposable workspace trees."
    }))
];
function parseIgnoreFileRules(content) {
    return content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).map((line) => ({
        pattern: line.startsWith("!") ? line.slice(1) : line,
        decision: line.startsWith("!") ? "include" : "exclude",
        rationale: "Rule supplied by supported ignore-file evidence."
    }));
}
function createIgnorePolicy(options) {
    const workspaceRoot = node_path_1.default.resolve(options.workspaceRoot);
    const sources = [
        { id: "product-defaults", kind: "default", rules: DEFAULT_SCAN_RULES },
        { id: "workspace-configuration", kind: "configuration", rules: options.configuredRules ?? [] },
        { id: "ignore-file-evidence", kind: "ignore-file", rules: options.ignoreFileRules ?? [] },
        { id: "invocation-overrides", kind: "invocation", rules: options.invocationRules ?? [] }
    ];
    return { version: exports.IGNORE_POLICY_VERSION, id: `ignore-policy-v${exports.IGNORE_POLICY_VERSION}`, workspaceRoot, sources };
}
function normalizeWorkspaceRelativePath(workspaceRoot, requestedPath) {
    if (!requestedPath.trim() || node_path_1.default.isAbsolute(requestedPath))
        throw new Error("Path must be a non-empty workspace-relative path.");
    const normalized = node_path_1.default.posix.normalize(requestedPath.replace(/\\/g, "/")).replace(/^\.\//, "");
    if (normalized === ".." || normalized.startsWith("../") || normalized.includes("/../"))
        throw new Error("Path escapes the effective workspace.");
    const resolved = node_path_1.default.resolve(workspaceRoot, normalized);
    const relative = node_path_1.default.relative(node_path_1.default.resolve(workspaceRoot), resolved);
    if (relative === ".." || relative.startsWith(`..${node_path_1.default.sep}`) || node_path_1.default.isAbsolute(relative))
        throw new Error("Path escapes the effective workspace.");
    return normalized;
}
function ruleMatches(pattern, candidate) {
    const clean = pattern.replace(/^\//, "").replace(/\\/g, "/");
    if (clean.endsWith("/")) {
        const segment = clean.slice(0, -1);
        return candidate === segment || candidate.startsWith(`${segment}/`) || candidate.includes(`/${segment}/`);
    }
    const escaped = clean.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
    return new RegExp(`^(?:.*\/)?${escaped}(?:\/.*)?$`).test(candidate);
}
function explainIgnorePolicy(policy, requestedPath) {
    const base = {
        policyVersion: policy.version,
        policyId: policy.id,
        workspaceRoot: policy.workspaceRoot,
        requestedPath,
        contributingSources: policy.sources.map(({ id, kind, rules }) => ({ id, kind, ruleCount: rules.length }))
    };
    let normalizedPath;
    try {
        normalizedPath = normalizeWorkspaceRelativePath(policy.workspaceRoot, requestedPath);
    }
    catch (error) {
        return { ...base, decision: "invalid", containmentFailure: error instanceof Error ? error.message : String(error) };
    }
    let winningRule;
    for (const source of policy.sources)
        for (const rule of source.rules)
            if (ruleMatches(rule.pattern, normalizedPath))
                winningRule = { ...rule, sourceId: source.id, sourceKind: source.kind };
    return { ...base, normalizedPath, decision: winningRule?.decision ?? "include", winningRule };
}
exports.CANONICAL_DAY_SHIFT_LOCAL_IGNORE_RULES = Object.freeze([
    {
        path: ".day-shift/local.toml",
        rationale: "local.toml stores local machine/worktree overrides."
    },
    {
        path: "sandbox/",
        rationale: "Sandbox is the stable local-only disposable parent path."
    }
]);
exports.TRACKABLE_DAY_SHIFT_SHARED_ASSET_PATHS = Object.freeze([
    ".day-shift/agents.md",
    ".day-shift/config.toml",
    ".day-shift/prompts/",
    ".day-shift/workflows/",
    ".day-shift/templates/",
    ".day-shift/specs/"
]);
function getCanonicalDayShiftLocalIgnoreEntries() {
    return exports.CANONICAL_DAY_SHIFT_LOCAL_IGNORE_RULES.map((rule) => rule.path);
}
function renderCanonicalIgnoreInstallContractText() {
    const lines = [
        "Canonical Day Shift ignore-install contract (v1)",
        "",
        "Local-only ignore entries:",
        ...exports.CANONICAL_DAY_SHIFT_LOCAL_IGNORE_RULES.map((rule) => `- ${rule.path} (${rule.rationale})`),
        "",
        "Shared Day Shift assets that remain trackable:",
        ...exports.TRACKABLE_DAY_SHIFT_SHARED_ASSET_PATHS.map((assetPath) => `- ${assetPath}`)
    ];
    return lines.join("\n");
}
function createIgnoreInstallPreview(repositoryRoot) {
    const gitignorePath = node_path_1.default.resolve(repositoryRoot, ".gitignore");
    const gitignoreExists = node_fs_1.default.existsSync(gitignorePath);
    const existingContent = gitignoreExists
        ? node_fs_1.default.readFileSync(gitignorePath, "utf8")
        : "";
    const existingLines = existingContent
        .split(/\r?\n/)
        .map((line) => line.replace(/\r$/, ""));
    const normalizedExistingLines = (0, preview_normalization_1.collectNormalizedIgnoreEntries)(existingLines);
    const canonicalEntries = getCanonicalDayShiftLocalIgnoreEntries();
    const existingCanonicalEntries = canonicalEntries.filter((entry) => normalizedExistingLines.has((0, preview_normalization_1.normalizeCanonicalEntryForComparison)(entry)));
    const proposedAdditions = canonicalEntries.filter((entry) => !normalizedExistingLines.has((0, preview_normalization_1.normalizeCanonicalEntryForComparison)(entry)));
    let outcome = "already-installed";
    if (proposedAdditions.length > 0) {
        outcome = gitignoreExists ? "append" : "create-file";
    }
    return {
        repositoryRoot,
        gitignorePath,
        gitignoreExists,
        canonicalEntries,
        existingCanonicalEntries,
        proposedAdditions,
        outcome
    };
}
function applyIgnoreInstallPreview(preview) {
    if (preview.proposedAdditions.length === 0) {
        return {
            changed: false,
            action: "none",
            writtenEntries: []
        };
    }
    if (!preview.gitignoreExists) {
        node_fs_1.default.writeFileSync(preview.gitignorePath, `${preview.proposedAdditions.join("\n")}\n`, "utf8");
        return {
            changed: true,
            action: "create-file",
            writtenEntries: preview.proposedAdditions
        };
    }
    const existingContent = node_fs_1.default.readFileSync(preview.gitignorePath, "utf8");
    const separator = existingContent.length > 0 && !existingContent.endsWith("\n")
        ? "\n"
        : "";
    const nextContent = `${existingContent}${separator}${preview.proposedAdditions.join("\n")}\n`;
    node_fs_1.default.writeFileSync(preview.gitignorePath, nextContent, "utf8");
    return {
        changed: true,
        action: "append",
        writtenEntries: preview.proposedAdditions
    };
}
