import { resolve } from "node:path";
import { mkdirSync, writeFileSync } from "node:fs";
import Replicate from "replicate";
import { nanoid } from "nanoid";
import { readToken } from "../lib/replicate-key.js";
// ---------------------------------------------------------------------------
// Model registry
// ---------------------------------------------------------------------------
const MODELS = {
    "nano-banana-pro": { id: "google/nano-banana-pro" },
    "recraft-v4": { id: "recraft-ai/recraft-v4", svgId: "recraft-ai/recraft-v4-svg" },
    "flux-schnell": { id: "black-forest-labs/flux-schnell" },
};
// ---------------------------------------------------------------------------
// Aspect ratio → width/height for models that need explicit dimensions
// ---------------------------------------------------------------------------
const ASPECT_RATIOS = {
    "1:1": { width: 1024, height: 1024 },
    "4:3": { width: 1024, height: 768 },
    "3:2": { width: 1024, height: 683 },
    "16:9": { width: 1024, height: 576 },
    "21:9": { width: 1344, height: 576 },
    "9:16": { width: 576, height: 1024 },
};
export async function imageGenerate(input, accountId, platformRoot) {
    const { prompt, model, aspectRatio = "1:1", outputFormat = "png" } = input;
    // --- Token check ---
    const tokenResult = readToken();
    if (!tokenResult) {
        console.error(`[image-generate] no-token`);
        return {
            content: [{ type: "text", text: "No Replicate API token configured. Run replicate-key-store to set one." }],
            isError: true,
        };
    }
    // --- SVG validation ---
    if (outputFormat === "svg" && model !== "recraft-v4") {
        return {
            content: [{ type: "text", text: "SVG output is only available with recraft-v4." }],
            isError: true,
        };
    }
    // --- Resolve model ID ---
    const modelEntry = MODELS[model];
    if (!modelEntry) {
        return {
            content: [{ type: "text", text: `Unknown model: ${model}` }],
            isError: true,
        };
    }
    const modelId = outputFormat === "svg" && modelEntry.svgId ? modelEntry.svgId : modelEntry.id;
    console.error(`[image-generate] start model=${model} format=${outputFormat} aspect=${aspectRatio}`);
    const startMs = Date.now();
    // --- Build model input ---
    const dimensions = ASPECT_RATIOS[aspectRatio] ?? ASPECT_RATIOS["1:1"];
    const modelInput = {
        prompt,
        width: dimensions.width,
        height: dimensions.height,
    };
    // Some models accept aspect_ratio directly instead of width/height
    if (model === "flux-schnell") {
        modelInput.aspect_ratio = aspectRatio;
        delete modelInput.width;
        delete modelInput.height;
    }
    if (outputFormat !== "svg") {
        modelInput.output_format = outputFormat;
    }
    // --- Call Replicate ---
    const replicate = new Replicate({ auth: tokenResult.token });
    let output;
    try {
        output = await replicate.run(modelId, { input: modelInput });
    }
    catch (err) {
        const latencyMs = Date.now() - startMs;
        const msg = err instanceof Error ? err.message : String(err);
        // Auth errors from the SDK
        if (msg.includes("401") || msg.includes("403") || msg.includes("Unauthorized") || msg.includes("authentication")) {
            console.error(`[image-generate] auth-error status=401 latency=${latencyMs}ms`);
            return {
                content: [{ type: "text", text: "Replicate API token was rejected — it may be invalid or revoked." }],
                isError: true,
            };
        }
        // Network errors
        if (msg.includes("ECONNREFUSED") || msg.includes("ENOTFOUND") || msg.includes("ETIMEDOUT") || msg.includes("fetch failed")) {
            console.error(`[image-generate] network-error error=${msg} latency=${latencyMs}ms`);
            return {
                content: [{ type: "text", text: "Replicate API is unreachable — check network or try again." }],
                isError: true,
            };
        }
        // Model/generation errors
        console.error(`[image-generate] model-error model=${model} error=${msg} latency=${latencyMs}ms`);
        return {
            content: [{ type: "text", text: `Image generation failed: ${msg}` }],
            isError: true,
        };
    }
    // --- Extract image URL from output ---
    // Replicate output varies by model: string URL, FileOutput, or array thereof.
    // FileOutput has a url() method (returns URL object) and toString() which in some
    // SDK versions returns a CSS-wrapped url(https://...) rather than a bare URL.
    const extractUrl = (val) => {
        if (typeof val === "string")
            return val.startsWith("http") ? val : null;
        if (!val || typeof val !== "object")
            return null;
        const obj = val;
        if (typeof obj["url"] === "function") {
            try {
                return obj["url"]().href;
            }
            catch { /* fall through */ }
        }
        let str = String(val);
        if (str.startsWith("url(") && str.endsWith(")"))
            str = str.slice(4, -1);
        return str.startsWith("http") ? str : null;
    };
    let imageUrl = null;
    if (Array.isArray(output)) {
        for (const item of output) {
            const u = extractUrl(item);
            if (u) {
                imageUrl = u;
                break;
            }
        }
    }
    else {
        imageUrl = extractUrl(output);
    }
    if (!imageUrl) {
        const latencyMs = Date.now() - startMs;
        console.error(`[image-generate] model-error model=${model} error=no-url-in-output latency=${latencyMs}ms`);
        return {
            content: [{ type: "text", text: `Image generation returned unexpected output format.` }],
            isError: true,
        };
    }
    // --- Download image ---
    let imageBuffer;
    try {
        const res = await fetch(imageUrl);
        if (!res.ok) {
            throw new Error(`HTTP ${res.status}`);
        }
        imageBuffer = Buffer.from(await res.arrayBuffer());
    }
    catch (err) {
        const latencyMs = Date.now() - startMs;
        const msg = err instanceof Error ? err.message : String(err);
        console.error(`[image-generate] download-error url=${imageUrl} error=${msg} latency=${latencyMs}ms`);
        return {
            content: [{ type: "text", text: `Image was generated but download failed: ${msg}` }],
            isError: true,
        };
    }
    // --- Persist to disk ---
    const ext = outputFormat === "svg" ? "svg" : outputFormat;
    const date = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
    const filename = `${date}-${nanoid(6)}.${ext}`;
    const accountDir = resolve(platformRoot, "..", "data/accounts", accountId);
    const generatedDir = resolve(accountDir, "generated");
    const filePath = resolve(generatedDir, filename);
    try {
        mkdirSync(generatedDir, { recursive: true });
        writeFileSync(filePath, imageBuffer);
    }
    catch (err) {
        const latencyMs = Date.now() - startMs;
        const msg = err instanceof Error ? err.message : String(err);
        console.error(`[image-generate] disk-error file=${filePath} error=${msg} latency=${latencyMs}ms`);
        return {
            content: [{ type: "text", text: `Image was generated but could not be saved — disk may be full or path inaccessible.` }],
            isError: true,
        };
    }
    const latencyMs = Date.now() - startMs;
    console.error(`[image-generate] complete model=${model} latency=${latencyMs}ms file=${filePath}`);
    const modelDesc = {
        "nano-banana-pro": "photorealistic, data-driven visuals",
        "recraft-v4": "design compositions, branded assets",
        "flux-schnell": "fast drafts, concept sketches",
    };
    return {
        content: [{
                type: "text",
                text: [
                    `Image generated (${model}, ${outputFormat}, ${aspectRatio}):`,
                    `  URL: /generated/${filename}`,
                    `  File: ${filePath}`,
                    `  Model: ${model} (${modelDesc[model] ?? model})`,
                ].join("\n"),
            }],
    };
}
//# sourceMappingURL=image-generate.js.map