/**
 * Auto-Resolve Merged Branches Use Case
 *
 * Detects features in the Review lifecycle whose remote branches have already
 * been merged, and transitions them to Maintain. This resolves stale
 * "action needed" states that are out of sync with the actual git/PR state.
 *
 * Called on dashboard page load to ensure the UI reflects reality.
 *
 * Strategy per feature:
 * 1. If the feature has PR data, check PR status via batch `listPrStatuses`.
 *    If the PR is Merged, transition to Maintain.
 * 2. If the feature has no PR data, check if the branch is merged into the
 *    default branch using `verifyMerge` (git merge-base).
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { injectable, inject } from 'tsyringe';
import { SdlcLifecycle, PrStatus, AgentRunStatus } from '../../../domain/generated/output.js';
import { UpdateFeatureLifecycleUseCase } from './update/update-feature-lifecycle.use-case.js';
let AutoResolveMergedBranchesUseCase = class AutoResolveMergedBranchesUseCase {
    featureRepo;
    gitPrService;
    agentRunRepo;
    updateLifecycle;
    constructor(featureRepo, gitPrService, agentRunRepo, updateLifecycle) {
        this.featureRepo = featureRepo;
        this.gitPrService = gitPrService;
        this.agentRunRepo = agentRunRepo;
        this.updateLifecycle = updateLifecycle;
    }
    async execute(features) {
        const reviewFeatures = features.filter((f) => f.lifecycle === SdlcLifecycle.Review && f.repositoryPath);
        if (reviewFeatures.length === 0) {
            return { resolvedCount: 0, resolvedFeatureIds: [] };
        }
        // Group by repository for batch PR status queries
        const byRepo = new Map();
        for (const feature of reviewFeatures) {
            const group = byRepo.get(feature.repositoryPath) ?? [];
            group.push(feature);
            byRepo.set(feature.repositoryPath, group);
        }
        const resolvedFeatureIds = [];
        for (const [repoPath, repoFeatures] of byRepo) {
            const resolved = await this.processRepository(repoPath, repoFeatures);
            resolvedFeatureIds.push(...resolved);
        }
        return {
            resolvedCount: resolvedFeatureIds.length,
            resolvedFeatureIds,
        };
    }
    async processRepository(repoPath, features) {
        const resolvedIds = [];
        // Check if repo has a remote — skip if not
        let hasRemote;
        try {
            hasRemote = await this.gitPrService.hasRemote(repoPath);
        }
        catch {
            return resolvedIds;
        }
        if (!hasRemote) {
            // No remote — try local merge verification for features without PRs
            return this.checkLocalMergeStatus(repoPath, features);
        }
        // Batch-fetch PR statuses for this repo
        let prStatuses;
        try {
            prStatuses = await this.gitPrService.listPrStatuses(repoPath);
        }
        catch {
            // gh CLI not available or rate limited — fall back to local checks
            return this.checkLocalMergeStatus(repoPath, features);
        }
        // Build lookup maps
        const statusByNumber = new Map();
        const statusByBranch = new Map();
        for (const pr of prStatuses) {
            statusByNumber.set(pr.number, pr);
            if (pr.headRefName) {
                const existing = statusByBranch.get(pr.headRefName);
                // Prefer Merged PRs for resolution detection
                if (!existing || pr.state === PrStatus.Merged) {
                    statusByBranch.set(pr.headRefName, pr);
                }
            }
        }
        for (const feature of features) {
            const resolved = await this.checkFeature(feature, statusByNumber, statusByBranch, repoPath);
            if (resolved) {
                resolvedIds.push(feature.id);
            }
        }
        return resolvedIds;
    }
    async checkFeature(feature, statusByNumber, statusByBranch, repoPath) {
        // Strategy 1: Feature has PR data — check if PR is merged
        if (feature.pr?.number) {
            const prInfo = statusByNumber.get(feature.pr.number);
            if (prInfo?.state === PrStatus.Merged) {
                return this.resolveFeature(feature);
            }
        }
        // Strategy 2: Match by branch name — find a merged PR for this branch
        const branchPr = statusByBranch.get(feature.branch);
        if (branchPr?.state === PrStatus.Merged) {
            // Update the feature's PR data to reflect the merged PR
            const freshFeature = await this.featureRepo.findById(feature.id);
            if (freshFeature && freshFeature.lifecycle === SdlcLifecycle.Review) {
                freshFeature.pr = {
                    ...(freshFeature.pr ?? {
                        url: branchPr.url,
                        number: branchPr.number,
                        status: PrStatus.Open,
                    }),
                    status: PrStatus.Merged,
                };
                await this.featureRepo.update(freshFeature);
            }
            return this.resolveFeature(feature);
        }
        // Strategy 3: No PR match — check if branch is merged locally
        return this.checkLocalMergeForFeature(repoPath, feature);
    }
    async checkLocalMergeStatus(repoPath, features) {
        const resolvedIds = [];
        for (const feature of features) {
            const resolved = await this.checkLocalMergeForFeature(repoPath, feature);
            if (resolved) {
                resolvedIds.push(feature.id);
            }
        }
        return resolvedIds;
    }
    async checkLocalMergeForFeature(repoPath, feature) {
        try {
            const defaultBranch = await this.gitPrService.getDefaultBranch(repoPath);
            const isMerged = await this.gitPrService.verifyMerge(repoPath, feature.branch, defaultBranch);
            if (isMerged) {
                return this.resolveFeature(feature);
            }
        }
        catch {
            // Branch may not exist locally, git errors — skip silently
        }
        return false;
    }
    async resolveFeature(feature) {
        // Re-fetch to avoid races with other processes
        const freshFeature = await this.featureRepo.findById(feature.id);
        if (!freshFeature || freshFeature.lifecycle !== SdlcLifecycle.Review) {
            return false;
        }
        await this.updateLifecycle.execute({
            featureId: feature.id,
            lifecycle: SdlcLifecycle.Maintain,
        });
        // Mark agent run as completed if one exists
        if (freshFeature.agentRunId) {
            try {
                await this.agentRunRepo.updateStatus(freshFeature.agentRunId, AgentRunStatus.completed);
            }
            catch {
                // Non-critical — agent run may already be completed
            }
        }
        return true;
    }
};
AutoResolveMergedBranchesUseCase = __decorate([
    injectable(),
    __param(0, inject('IFeatureRepository')),
    __param(1, inject('IGitPrService')),
    __param(2, inject('IAgentRunRepository')),
    __param(3, inject(UpdateFeatureLifecycleUseCase)),
    __metadata("design:paramtypes", [Object, Object, Object, UpdateFeatureLifecycleUseCase])
], AutoResolveMergedBranchesUseCase);
export { AutoResolveMergedBranchesUseCase };
