"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 __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.ACCEPTED_CONFLICT_MARKER = void 0;
exports.buildAcceptedMergeComment = buildAcceptedMergeComment;
exports.buildAcceptedConflictComment = buildAcceptedConflictComment;
exports.buildAcceptedMergeFailureComment = buildAcceptedMergeFailureComment;
exports.hasAlreadyNotifiedConflict = hasAlreadyNotifiedConflict;
exports.resolveDoneStatus = resolveDoneStatus;
exports.acceptedCommand = acceptedCommand;
const logger_1 = require("../logger");
const github_1 = require("../github");
const git = __importStar(require("../git"));
const run_1 = require("./run");
const DONE_STATUS_CANDIDATES = ['done', 'closed', 'finish', 'success', 'prod'];
/**
 * Stable phrase embedded in the conflict comment so we can detect a previously
 * posted notice on later cron ticks and avoid spamming the ticket. Changing
 * this phrase will cause one duplicate notice on tickets that already received
 * a notice from a previous version.
 */
exports.ACCEPTED_CONFLICT_MARKER = 'has merge conflicts and cannot be auto-merged';
/**
 * Comment posted on the task immediately before merging an accepted PR (so the
 * ticket records that aidev is performing the merge).
 */
function buildAcceptedMergeComment(config, branchName) {
    return `${config.commentPrefix} Merging the accepted pull request for branch \`${branchName}\`.`;
}
/**
 * One-time notice posted when an accepted PR cannot be merged because of
 * conflicts. Phrased so {@link hasAlreadyNotifiedConflict} can detect it on
 * later runs.
 */
function buildAcceptedConflictComment(config, branchName, baseBranch) {
    return (`${config.commentPrefix} Cannot merge accepted pull request for branch \`${branchName}\` — ` +
        `the PR ${exports.ACCEPTED_CONFLICT_MARKER} with \`${baseBranch}\`. Resolve the conflicts ` +
        `(or retrigger the task to let aidev attempt resolution) before this can be merged.`);
}
/**
 * Comment posted when `gh pr merge` fails for a reason other than conflicts
 * (e.g. branch protection, required checks not green, missing approvals, gh
 * not authenticated). Includes the raw gh error so the user can act on it
 * without having to dig through aidev's local logs.
 */
function buildAcceptedMergeFailureComment(config, branchName, reason) {
    const trimmed = reason.trim() || 'no error message reported by gh';
    return (`${config.commentPrefix} Failed to merge accepted pull request for branch \`${branchName}\`.\n\n` +
        `Reason:\n\`\`\`\n${trimmed}\n\`\`\``);
}
function hasAlreadyNotifiedConflict(comments, commentPrefix) {
    return comments.some((c) => c.text.startsWith(commentPrefix) && c.text.includes(exports.ACCEPTED_CONFLICT_MARKER));
}
/**
 * Pick the configured done status, otherwise probe the board for one of the
 * common "done" names (done / closed / finish / success / prod). Returns null
 * when nothing matches and no override was given.
 */
async function resolveDoneStatus(config, provider) {
    if (config.doneStatus)
        return config.doneStatus;
    if (!provider.fetchAvailableStatuses)
        return null;
    let statuses;
    try {
        statuses = await provider.fetchAvailableStatuses();
    }
    catch (err) {
        logger_1.logger.debug(`Could not fetch available statuses to auto-detect DONE_STATUS: ${err instanceof Error ? err.message : String(err)}`);
        return null;
    }
    const byLower = new Map(statuses.map((s) => [s.toLowerCase(), s]));
    for (const candidate of DONE_STATUS_CANDIDATES) {
        const match = byLower.get(candidate);
        if (match)
            return match;
    }
    return null;
}
/**
 * Process "accepted" tasks: find tasks in review status with the accepted tag,
 * post a short merge notice on each ticket, merge their PRs via gh CLI (squash +
 * delete branch), update status to done, then checkout main and pull.
 */
async function acceptedCommand(config, provider) {
    if (!config.acceptedTag) {
        logger_1.logger.warn('ACCEPTED_TAG is not configured. Run "aidev init" to set it up.');
        return;
    }
    if (!(0, github_1.isGhInstalled)()) {
        logger_1.logger.warn('gh CLI is not installed. Install it from https://cli.github.com/');
        return;
    }
    if (!(0, github_1.isGhAuthenticated)()) {
        logger_1.logger.warn('gh CLI is not authenticated. Run "gh auth login" first.');
        return;
    }
    const reviewStatus = (0, run_1.getInReviewStatus)(config);
    logger_1.logger.info(`Fetching tasks in "${reviewStatus}" status...`);
    const tasks = await provider.fetchTasksByStatus([reviewStatus]);
    const acceptedTag = config.acceptedTag.toLowerCase();
    const acceptedTasks = tasks.filter((t) => t.tags.some((tag) => tag.toLowerCase() === acceptedTag));
    if (acceptedTasks.length === 0) {
        logger_1.logger.info('No accepted tasks found.');
        return;
    }
    logger_1.logger.info(`Found ${acceptedTasks.length} accepted task(s)`);
    const doneStatus = await resolveDoneStatus(config, provider);
    if (!config.doneStatus) {
        if (doneStatus) {
            logger_1.logger.info(`DONE_STATUS not configured — using detected status "${doneStatus}"`);
        }
        else {
            logger_1.logger.warn(`DONE_STATUS not configured and no matching status (${DONE_STATUS_CANDIDATES.join(', ')}) found on the board — task status will not be updated after merge.`);
        }
    }
    let merged = 0;
    for (const task of acceptedTasks) {
        const branchName = `${task.id}/${git.slugify(task.name)}`;
        logger_1.logger.task(`[${task.id}] "${task.name}" — merging branch ${branchName}`);
        const mergeability = (0, github_1.getPullRequestMergeability)(branchName);
        if (mergeability === 'CONFLICTING') {
            let existingComments = [];
            try {
                existingComments = await provider.getComments(task.id);
            }
            catch (err) {
                logger_1.logger.warn(`[${task.id}] Failed to fetch comments to check for prior conflict notice: ${err instanceof Error ? err.message : String(err)}`);
            }
            if (hasAlreadyNotifiedConflict(existingComments, config.commentPrefix)) {
                logger_1.logger.info(`[${task.id}] Skipping — PR has merge conflicts and the ticket was already notified.`);
                continue;
            }
            try {
                await provider.postComment(task.id, buildAcceptedConflictComment(config, branchName, config.githubBaseBranch));
                logger_1.logger.warn(`[${task.id}] PR has merge conflicts with ${config.githubBaseBranch} — posted notice and skipping.`);
            }
            catch (err) {
                logger_1.logger.warn(`[${task.id}] Failed to post conflict notice: ${err instanceof Error ? err.message : String(err)}`);
            }
            continue;
        }
        try {
            await provider.postComment(task.id, buildAcceptedMergeComment(config, branchName));
        }
        catch (err) {
            logger_1.logger.warn(`[${task.id}] Failed to post merge notice: ${err instanceof Error ? err.message : String(err)}`);
            continue;
        }
        const result = (0, github_1.mergePullRequest)(branchName);
        if (!result.success) {
            logger_1.logger.error(`[${task.id}] Failed to merge PR: ${result.error}`);
            try {
                await provider.postComment(task.id, buildAcceptedMergeFailureComment(config, branchName, result.error));
            }
            catch (err) {
                logger_1.logger.warn(`[${task.id}] Failed to post merge-failure notice: ${err instanceof Error ? err.message : String(err)}`);
            }
            continue;
        }
        logger_1.logger.success(`[${task.id}] PR merged successfully`);
        if (doneStatus) {
            try {
                await provider.updateStatus(task.id, doneStatus);
                logger_1.logger.info(`[${task.id}] Status updated to "${doneStatus}"`);
            }
            catch (err) {
                logger_1.logger.warn(`[${task.id}] Failed to update status: ${err instanceof Error ? err.message : String(err)}`);
            }
        }
        merged++;
    }
    if (merged > 0) {
        logger_1.logger.info(`Checking out ${config.githubBaseBranch} and pulling latest...`);
        const ok = git.fetchAndCheckout(config.gitRemote, config.githubBaseBranch);
        if (!ok) {
            logger_1.logger.error(`Failed to checkout ${config.githubBaseBranch}`);
        }
    }
    logger_1.logger.success(`Done. Merged: ${merged}/${acceptedTasks.length}`);
}
//# sourceMappingURL=accepted.js.map