import path from "node:path";
import { getPortableStateSpecs, getSurfaceSpecs } from "./router.js";
import { writeLatestTaskPacketSet } from "./state.js";
import { renderCodexBody } from "../adapters/codex.js";
import { renderClaudeBody } from "../adapters/claude.js";
import { renderCopilotBody } from "../adapters/copilot.js";
import { applyWritePlan, fileContainsManagedFile, normalizeRepoPath, pathExists, planCreateOnlyFile, planManagedBlock, planManagedFile, readText, relativeFrom, renderTemplate } from "../utils/fs.js";
export async function initOrSyncTarget(repoRoot, targetRoot, config, context, options = {}) {
    const plans = [];
    for (const item of getPortableStateSpecs(config, context)) {
        const template = await readText(path.join(repoRoot, item.templatePath));
        const body = renderTemplate(template, {
            projectName: context.projectName,
            generatedAt: context.generatedAt,
            taskDirectory: context.taskDirectory,
            contextDirectory: context.contextDirectory,
            targetRoot: context.targetRoot,
            profileName: context.profileName,
            executionMode: context.executionMode,
            projectType: context.projectType,
            profileSource: context.profileSource,
            starterSpecialists: context.starterSpecialists,
            starterValidations: context.starterValidations,
            starterMcpHints: context.starterMcpHints,
            ...(item.templateValues ?? {})
        });
        const outputPath = path.join(targetRoot, item.outputPath);
        plans.push(item.writeMode === "seed-only"
            ? await planCreateOnlyFile(outputPath, item.logicalName, body, { managed: item.contentFormat !== "raw" })
            : await planManagedFile(outputPath, item.logicalName, body));
    }
    for (const surface of getSurfaceSpecs(config)) {
        const outputPath = path.join(targetRoot, surface.file);
        const body = await renderSurfaceBody(repoRoot, config, context, surface.tool);
        if (!(await pathExists(outputPath))) {
            plans.push(await planManagedFile(outputPath, surface.file, body));
            continue;
        }
        if (await fileContainsManagedFile(outputPath, surface.file)) {
            plans.push(await planManagedFile(outputPath, surface.file, body));
            continue;
        }
        plans.push(await planManagedBlock(outputPath, surface.blockName, body));
    }
    return applyPlans(targetRoot, plans, options);
}
export async function writeTaskPackets(targetRoot, packets) {
    const results = [];
    for (const packet of packets) {
        const plan = await planManagedFile(path.join(targetRoot, packet.relativePath), packet.logicalName, packet.content);
        results.push(await applyWritePlan(plan));
    }
    await writeLatestTaskPacketSet(targetRoot, packets.map((packet) => packet.relativePath));
    return results;
}
export function summarizeWrites(results, targetRoot, options = {}) {
    const lines = results.map((result) => {
        const relativePath = relativeFrom(targetRoot, result.path) || ".";
        const diff = options.diffSummary || options.dryRun ? `, +${result.addedLines ?? 0}/-${result.removedLines ?? 0}` : "";
        const backup = result.backupPath ? `, backup=${relativeFrom(targetRoot, result.backupPath)}` : "";
        return `- ${result.status}: ${relativePath} (${result.detail}${diff}${backup})`;
    });
    return lines.join("\n");
}
async function renderSurfaceBody(repoRoot, config, context, tool) {
    switch (tool) {
        case "codex":
            return renderCodexBody(repoRoot, config, context);
        case "claude":
            return renderClaudeBody(repoRoot, config, context);
        case "copilot":
            return renderCopilotBody(repoRoot, config, context);
    }
}
async function applyPlans(targetRoot, plans, options) {
    const results = [];
    const backupRoot = options.backup && !options.dryRun
        ? path.join(targetRoot, ".agent", "backups", "shrey-junior", options.backupLabel ?? new Date().toISOString().replace(/[:.]/g, "-"))
        : undefined;
    for (const plan of plans) {
        if (options.dryRun) {
            results.push({
                path: plan.path,
                status: plan.status,
                detail: `dry-run ${plan.detail}`,
                ...(plan.addedLines !== undefined ? { addedLines: plan.addedLines } : {}),
                ...(plan.removedLines !== undefined ? { removedLines: plan.removedLines } : {})
            });
            continue;
        }
        const backupPath = backupRoot && plan.currentContent !== undefined && plan.status !== "unchanged" && plan.status !== "conflict"
            ? path.join(backupRoot, normalizeRepoPath(relativeFrom(targetRoot, plan.path)))
            : undefined;
        results.push(await applyWritePlan(plan, backupPath ? { backupPath } : undefined));
    }
    return results;
}
