import { randomUUID } from "node:crypto";
import { resolve } from "node:path";
import { canonicalPullRequestUrl, fetchPullRequestDetails, fetchPullRequestDiff, fetchPullRequestReviewActivity } from "github-review";
import { spawn } from "@poe-code/agent-spawn";
import { discoverCodeReviewProfiles, loadCodeReviewProfile, loadCodeReviewPrompt, loadCodeReviewRolePrompt } from "./assets.js";
import { loadDefaultPoeCodeAgent, resolveCodeReviewRuntimeOptions } from "./config.js";
import { createCodeReviewAgentMcpConfig } from "./mcp.js";
import { buildCodeReviewOrchestratorPrompt } from "./prompt-builders.js";
import { shouldUseTextStdinForCodeReview } from "./prompt-transport.js";
import { CodeReviewYamlStore, resolveCodeReviewStoreDirectory } from "./review-store.js";
export async function runCodeReview(input, dependencies = {}) {
    const unresolvedOptions = await (dependencies.resolveOptions ?? resolveCodeReviewRuntimeOptions)(input);
    const options = {
        ...unresolvedOptions,
        cwd: resolve(unresolvedOptions.cwd),
        prUrl: canonicalPullRequestUrl(unresolvedOptions.prUrl)
    };
    const agent = options.agent ??
        (await (dependencies.resolveAgent
            ? dependencies.resolveAgent()
            : loadDefaultPoeCodeAgent({ cwd: options.cwd })));
    if (!agent?.trim()) {
        throw new Error("No code-review agent resolved; configure codeReview.agent or the normal poe-code core.defaultAgent / POE_DEFAULT_AGENT setting.");
    }
    const profiles = await discoverCodeReviewProfiles({
        cwd: options.cwd,
        filters: options.profiles,
        profileDirectories: options.profileDirectories
    });
    const [profile, promptTemplate, prDetails, diff, priorActivity] = await Promise.all([
        resolveProfile(input, options, profiles),
        resolvePrompt(input, options),
        (dependencies.fetchPr ?? fetchPrWithCwd)(options.prUrl, options.cwd),
        (dependencies.fetchDiff ?? fetchDiffWithCwd)(options.prUrl, options.cwd),
        (dependencies.fetchComments ?? fetchCommentsWithCwd)(options.prUrl, options.cwd)
    ]);
    const requestedSessionId = options.sessionId ?? dependencies.createSessionId?.() ?? randomUUID();
    const draftStore = absoluteDraftStore(options);
    const store = dependencies.store ?? new CodeReviewYamlStore({ directory: draftStore });
    const activeRun = await store.startRun({
        sessionId: requestedSessionId,
        prUrl: options.prUrl,
        selectedAgent: agent,
        selectedProfiles: profiles.map(({ name }) => name)
    });
    const sessionId = activeRun.sessionId;
    await store.appendOrchestratorAction(options.prUrl, {
        action: "spawned_orchestrator",
        details: agent
    });
    const prompt = buildCodeReviewOrchestratorPrompt({
        input: options,
        profiles,
        profile,
        promptTemplate,
        prDetails,
        diff,
        priorActivity
    });
    const mcpConfig = createCodeReviewAgentMcpConfig({
        role: "orchestrator",
        session: sessionId,
        actor: "orchestrator",
        cwd: options.cwd,
        draftStore,
        agent,
        profileDirectories: options.profileDirectories,
        ...(options.profiles ? { profiles: options.profiles } : {})
    });
    const spawnResult = await (dependencies.spawnAgent ?? spawnWithPoeCode)(agent, prompt, {
        cwd: options.cwd,
        mcpServers: {
            "code-review": {
                command: mcpConfig.command,
                args: mcpConfig.args
            }
        }
    });
    if (spawnResult.exitCode !== 0) {
        throw new Error(`Code-review orchestrator failed: ${spawnResult.stderr || `exit ${spawnResult.exitCode}`}`);
    }
    const state = await store.read(options.prUrl);
    if (!state?.mergedReview) {
        throw new Error("Code-review orchestrator must create exactly one merged review.");
    }
    await store.appendOrchestratorAction(options.prUrl, {
        action: "completed_orchestration"
    });
    return {
        sessionId,
        state: (await store.read(options.prUrl)) ?? state,
        prompt,
        spawnResult
    };
}
async function resolveProfile(input, options, profiles) {
    if (input.profile !== undefined) {
        return input.profile;
    }
    if (options.profilePath) {
        return loadCodeReviewProfile(resolve(options.cwd, options.profilePath));
    }
    return profiles.map((profile) => `## ${profile.name}\n\n${profile.content.trim()}`).join("\n\n");
}
async function resolvePrompt(input, options) {
    if (input.prompt !== undefined) {
        return input.prompt;
    }
    return options.promptPath
        ? loadCodeReviewPrompt(resolve(options.cwd, options.promptPath))
        : loadCodeReviewRolePrompt({ cwd: options.cwd, role: "orchestrator" });
}
function absoluteDraftStore(input) {
    return resolveCodeReviewStoreDirectory(input.cwd, input.draftStore);
}
function fetchPrWithCwd(prUrl, cwd) {
    return fetchPullRequestDetails(prUrl, undefined, { cwd });
}
function fetchDiffWithCwd(prUrl, cwd) {
    return fetchPullRequestDiff(prUrl, { cwd });
}
function fetchCommentsWithCwd(prUrl, cwd) {
    return fetchPullRequestReviewActivity(prUrl, { cwd });
}
async function spawnWithPoeCode(agent, prompt, options) {
    return spawn(agent, {
        prompt,
        ...options,
        ...(shouldUseTextStdinForCodeReview(agent) ? { useStdin: true } : {})
    });
}
