"use strict";
/**
 * `vyuh-dxkit setup-branch-protection` — configures branch protection
 * on the repo's default branch with dxkit's guardrail workflow listed
 * as a required status check. Without this step, the dxkit-guardrails
 * workflow we install only runs informationally — PRs can merge even
 * if the guardrail fails. With it, merges are blocked on guardrail
 * failures.
 *
 * Wraps `gh api -X PUT repos/{owner}/{repo}/branches/{branch}/protection`
 * with a JSON payload that:
 *   1. Adds `dxkit-guardrails` to required status checks
 *   2. Preserves any other required checks already configured
 *      (idempotent merge — don't clobber customer policy)
 *   3. Doesn't force a review-count policy by default (set --require-reviews=N if wanted)
 *
 * Edge cases handled:
 *   - gh CLI missing → preflight fails with clear install instructions
 *   - No github.com remote → resolveOwnerRepo throws GhError with suggestion
 *   - Customer not admin (HTTP 403) → ghApi throws with admin-asks suggestion
 *   - Workflow file missing → warn before applying (the protection rule
 *     would otherwise block ALL PRs until the workflow exists)
 *   - Existing protection rule with different required checks → merge
 *     dxkit-guardrails into the list instead of replacing
 */
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.runSetupBranchProtection = runSetupBranchProtection;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const logger = __importStar(require("./logger"));
const setup_gh_1 = require("./setup-gh");
const REQUIRED_CHECK = 'dxkit-guardrails';
function readExistingProtection(cwd, owner, repo, branch) {
    try {
        return (0, setup_gh_1.ghApi)(`repos/${owner}/${repo}/branches/${branch}/protection`, {
            cwd,
            method: 'GET',
        });
    }
    catch (e) {
        if (e instanceof setup_gh_1.GhError && e.httpStatus === 404) {
            // No protection rule exists yet — that's expected for the
            // common case where we're the first to configure one.
            return null;
        }
        throw e;
    }
}
/**
 * Build the protection payload by merging dxkit-guardrails into any
 * existing required-checks list. Preserves customer-configured
 * required checks, review counts, and admin-enforcement settings.
 */
function buildPayload(existing, opts) {
    // Existing required checks — preserve, then ensure dxkit-guardrails is in the set.
    const existingChecks = existing?.required_status_checks?.contexts ?? [];
    const mergedChecks = opts.force
        ? [REQUIRED_CHECK]
        : [...new Set([...existingChecks, REQUIRED_CHECK])];
    // Reviews policy — only override when the customer passed --require-reviews.
    // Without it, preserve whatever was there (or set null if no prior rule).
    let reviews = null;
    if (opts.requireReviews !== undefined && opts.requireReviews > 0) {
        reviews = {
            dismiss_stale_reviews: false,
            require_code_owner_reviews: false,
            required_approving_review_count: opts.requireReviews,
        };
    }
    else if (existing?.required_pull_request_reviews) {
        reviews = existing.required_pull_request_reviews;
    }
    return {
        required_status_checks: { strict: false, contexts: mergedChecks },
        enforce_admins: existing?.enforce_admins ?? false,
        required_pull_request_reviews: reviews,
        restrictions: null, // user/team push restrictions — out of scope here
    };
}
function checkWorkflowFile(cwd) {
    const wfPath = path.join(cwd, '.github', 'workflows', 'dxkit-guardrails.yml');
    return fs.existsSync(wfPath);
}
async function runSetupBranchProtection(cwd, opts = {}) {
    logger.header('vyuh-dxkit setup-branch-protection');
    if (!(0, setup_gh_1.preflightGhCli)('setup-branch-protection')) {
        process.exitCode = 1;
        return;
    }
    let ownerRepo;
    try {
        ownerRepo = (0, setup_gh_1.resolveOwnerRepo)(cwd);
    }
    catch (e) {
        if (e instanceof setup_gh_1.GhError) {
            process.exitCode = (0, setup_gh_1.renderGhError)(e, 'Resolve repo');
            return;
        }
        throw e;
    }
    const { owner, repo } = ownerRepo;
    const branch = opts.branch ?? (0, setup_gh_1.resolveDefaultBranch)(cwd);
    // Warn if the workflow file isn't present — protection-by-name would
    // otherwise block ALL PRs until the workflow is added.
    if (!checkWorkflowFile(cwd)) {
        logger.warn('No .github/workflows/dxkit-guardrails.yml found. Applying branch protection ' +
            'now would block every PR until that workflow exists.');
        logger.dim('  → Run `vyuh-dxkit init --with-ci --yes` first to scaffold the workflow.');
        process.exitCode = 1;
        return;
    }
    logger.info(`Resolving existing protection on ${owner}/${repo}#${branch}...`);
    let existing;
    try {
        existing = readExistingProtection(cwd, owner, repo, branch);
    }
    catch (e) {
        if (e instanceof setup_gh_1.GhError) {
            process.exitCode = (0, setup_gh_1.renderGhError)(e, 'Read existing protection');
            return;
        }
        throw e;
    }
    if (existing) {
        logger.info(`  → Found ${existing.required_status_checks?.contexts.length ?? 0} existing required check(s); ` +
            `dxkit-guardrails ${existing.required_status_checks?.contexts.includes(REQUIRED_CHECK)
                ? 'already in list'
                : 'will be merged in'}.`);
    }
    else {
        logger.info('  → No existing protection rule; creating one with dxkit-guardrails as required.');
    }
    const payload = buildPayload(existing, opts);
    logger.info(`Applying protection: required checks = [${payload.required_status_checks?.contexts.join(', ')}]; ` +
        `reviews required = ${payload.required_pull_request_reviews?.required_approving_review_count ?? 0}.`);
    try {
        (0, setup_gh_1.ghApi)(`repos/${owner}/${repo}/branches/${branch}/protection`, {
            cwd,
            method: 'PUT',
            inputJson: JSON.stringify(payload),
        });
    }
    catch (e) {
        if (e instanceof setup_gh_1.GhError) {
            process.exitCode = (0, setup_gh_1.renderGhError)(e, 'Apply protection');
            return;
        }
        throw e;
    }
    console.log(''); // slop-ok
    logger.success(`Branch protection applied to ${owner}/${repo}#${branch}.`);
    logger.dim(`  → Verify: https://github.com/${owner}/${repo}/settings/branches`);
    if (!payload.required_pull_request_reviews) {
        logger.dim('  → Review-count policy NOT changed (pass --require-reviews=N to require reviews).');
    }
}
//# sourceMappingURL=setup-branch-protection.js.map