/**
 * Rebase Feature on Main Use Case
 *
 * Rebases a feature branch onto the latest main branch with auto-sync
 * and agent-powered conflict resolution.
 *
 * Flow: resolve feature → create standalone agent run → record phase timing →
 * determine cwd (worktree or repo root) → sync main → rebase →
 * on conflict, delegate to ConflictResolutionService → complete timing.
 */
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 { randomUUID } from 'node:crypto';
import { GitPrError, GitPrErrorCode, } from '../../ports/output/services/git-pr-service.interface.js';
import { AgentRunStatus, AgentType } from '../../../domain/generated/output.js';
let RebaseFeatureOnMainUseCase = class RebaseFeatureOnMainUseCase {
    featureRepo;
    gitPrService;
    worktreeService;
    conflictResolutionService;
    agentRunRepo;
    phaseTimingRepo;
    constructor(featureRepo, gitPrService, worktreeService, conflictResolutionService, agentRunRepo, phaseTimingRepo) {
        this.featureRepo = featureRepo;
        this.gitPrService = gitPrService;
        this.worktreeService = worktreeService;
        this.conflictResolutionService = conflictResolutionService;
        this.agentRunRepo = agentRunRepo;
        this.phaseTimingRepo = phaseTimingRepo;
    }
    async execute(featureId) {
        // Resolve feature by exact ID or prefix
        const feature = (await this.featureRepo.findById(featureId)) ??
            (await this.featureRepo.findByIdPrefix(featureId));
        if (!feature) {
            throw new Error(`Feature not found: "${featureId}"`);
        }
        // Create standalone agent run + phase timing for activity timeline
        const now = new Date().toISOString();
        const agentRunId = randomUUID();
        const phaseTimingId = randomUUID();
        await this.agentRunRepo.create({
            id: agentRunId,
            agentType: AgentType.ClaudeCode,
            agentName: 'rebase',
            status: AgentRunStatus.running,
            prompt: `Rebase ${feature.branch} on main`,
            threadId: agentRunId,
            startedAt: now,
            featureId: feature.id,
            repositoryPath: feature.repositoryPath,
            createdAt: now,
            updatedAt: now,
        });
        await this.phaseTimingRepo.save({
            id: phaseTimingId,
            agentRunId,
            phase: 'rebase',
            startedAt: now,
            createdAt: now,
            updatedAt: now,
        });
        const startMs = Date.now();
        try {
            // Determine working directory — worktree path if it exists, else repo root
            const cwd = await this.resolveCwd(feature.repositoryPath, feature.branch);
            const defaultBranch = await this.gitPrService.getDefaultBranch(feature.repositoryPath);
            // Stash uncommitted changes if present (smart rebase)
            const didStash = await this.gitPrService.stash(cwd, `shep-auto-stash: ${feature.branch}`);
            let stashPopError;
            try {
                // Auto-sync main before rebasing (per spec decision)
                await this.gitPrService.syncMain(cwd, defaultBranch);
                // Attempt rebase
                try {
                    await this.gitPrService.rebaseOnMain(cwd, feature.branch, defaultBranch);
                }
                catch (error) {
                    if (error instanceof GitPrError && error.code === GitPrErrorCode.REBASE_CONFLICT) {
                        // Delegate to agent-powered conflict resolution
                        await this.conflictResolutionService.resolve(cwd, feature.branch, defaultBranch);
                    }
                    else {
                        throw error;
                    }
                }
            }
            finally {
                // Restore stashed changes after rebase (whether it succeeded or failed)
                if (didStash) {
                    try {
                        await this.gitPrService.stashPop(cwd);
                    }
                    catch {
                        // Stash pop failed — likely conflicts between rebased code and stashed changes.
                        // Invoke agent-powered resolution, then drop the stash entry on success.
                        try {
                            await this.conflictResolutionService.resolveStashPop(cwd, feature.branch, defaultBranch);
                            await this.gitPrService.stashDrop(cwd);
                        }
                        catch {
                            stashPopError = new Error(`Rebase succeeded but failed to restore your uncommitted changes. ` +
                                `The rebase is complete, but your stashed work-in-progress could not be applied cleanly. ` +
                                `Run \`git stash pop\` manually to resolve the remaining conflicts. ` +
                                `Your stash entry is preserved.`);
                        }
                    }
                }
            }
            // Throw stash pop error after the finally block to satisfy no-unsafe-finally
            if (stashPopError) {
                throw stashPopError;
            }
            // Rebase succeeded (possibly with resolved conflicts)
            await this.completeTiming(agentRunId, phaseTimingId, startMs, 'success');
        }
        catch (error) {
            // Record failure in timing
            const message = error instanceof Error ? error.message : String(error);
            await this.completeTiming(agentRunId, phaseTimingId, startMs, 'error', message);
            throw error;
        }
    }
    async completeTiming(agentRunId, phaseTimingId, startMs, exitCode, errorMessage) {
        const completedAt = new Date().toISOString();
        const durationMs = Date.now() - startMs;
        await this.phaseTimingRepo.update(phaseTimingId, {
            completedAt,
            durationMs: BigInt(durationMs),
            exitCode,
            ...(errorMessage && { errorMessage }),
        });
        await this.agentRunRepo.updateStatus(agentRunId, exitCode === 'success' ? AgentRunStatus.completed : AgentRunStatus.failed, { completedAt, ...(errorMessage && { error: errorMessage }) });
    }
    /**
     * Resolve the correct working directory for the feature.
     * Uses the worktree path if a worktree exists for this branch,
     * otherwise falls back to the repository root.
     */
    async resolveCwd(repositoryPath, branch) {
        const hasWorktree = await this.worktreeService.exists(repositoryPath, branch);
        if (hasWorktree) {
            return this.worktreeService.getWorktreePath(repositoryPath, branch);
        }
        return repositoryPath;
    }
};
RebaseFeatureOnMainUseCase = __decorate([
    injectable(),
    __param(0, inject('IFeatureRepository')),
    __param(1, inject('IGitPrService')),
    __param(2, inject('IWorktreeService')),
    __param(3, inject('IConflictResolutionService')),
    __param(4, inject('IAgentRunRepository')),
    __param(5, inject('IPhaseTimingRepository')),
    __metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object])
], RebaseFeatureOnMainUseCase);
export { RebaseFeatureOnMainUseCase };
