import fs from "node:fs/promises";
import path from "pathe";
import { Resource } from "../resource.js";
import { DockerApi } from "./api.js";
import { pushImageToRegistry } from "./registry.js";
/**
 * Build and manage a Docker image from a Dockerfile
 *
 * @example
 * // Build a Docker image from a Dockerfile
 * const appImage = await Image("app-image", {
 *   name: "myapp",
 *   tag: "latest",
 *   build: {
 *     context: "./app",
 *     dockerfile: "Dockerfile",
 *     buildArgs: {
 *       NODE_ENV: "production"
 *     }
 *   }
 * });
 */
export const Image = Resource("docker::Image", async function (id, props) {
    // Initialize Docker API client with the isolated config directory
    const api = new DockerApi();
    if (this.phase === "delete") {
        // No action needed for delete as Docker images aren't automatically removed
        // This is intentional as other resources might depend on the same image
        return this.destroy();
    }
    const tag = props.tag || "latest";
    const name = props.name ||
        (typeof props.image === "string"
            ? props.image
            : props.image?.name)?.split(":")[0] ||
        id;
    const imageRef = `${name}:${tag}`;
    let imageId;
    if (props.image) {
        const image = typeof props.image === "string" ? props.image : props.image.imageRef;
        const kind = typeof props.image === "object" && props.image.kind === "Image"
            ? "local"
            : "remote";
        if (kind === "remote") {
            await api.pullImage(image);
        }
        await api.tagImage(image, imageRef);
        // TODO: Extract image ID from pull output if available
    }
    else {
        let context;
        let dockerfile;
        if (props.build?.dockerfile && props.build?.context) {
            context = path.resolve(props.build.context);
            dockerfile = path.resolve(context, props.build.dockerfile);
        }
        else if (props.build?.dockerfile) {
            context = process.cwd();
            dockerfile = path.resolve(context, props.build.dockerfile);
        }
        else if (props.build?.context) {
            context = path.resolve(props.build.context);
            dockerfile = path.resolve(context, "Dockerfile");
        }
        else {
            context = process.cwd();
            dockerfile = path.resolve(context, "Dockerfile");
        }
        await fs.access(context);
        await fs.access(dockerfile);
        // Prepare build options
        const buildOptions = props.build?.args || {};
        // Add platform if specified
        const buildArgs = ["build", "-t", imageRef];
        if (props.build?.platform) {
            buildArgs.push("--platform", props.build.platform);
        }
        // Add target if specified
        if (props.build?.target) {
            buildArgs.push("--target", props.build.target);
        }
        // Add cache sources if specified
        if (props.build?.cacheFrom && props.build.cacheFrom.length > 0) {
            for (const cacheSource of props.build.cacheFrom) {
                buildArgs.push("--cache-from", cacheSource);
            }
        }
        // Add cache destinations if specified
        if (props.build?.cacheTo && props.build.cacheTo.length > 0) {
            for (const cacheTarget of props.build.cacheTo) {
                buildArgs.push("--cache-to", cacheTarget);
            }
        }
        // Add build arguments
        for (const [key, value] of Object.entries(buildOptions)) {
            buildArgs.push("--build-arg", `${key}=${value}`);
        }
        // Add build options if specified
        if (props.build?.options && props.build.options.length > 0) {
            buildArgs.push(...props.build.options);
        }
        buildArgs.push("-f", dockerfile);
        // Add context path
        buildArgs.push(context);
        // Execute build command
        const { stdout } = await api.exec(buildArgs);
        // Extract image ID from build output if available
        const imageIdMatch = /Successfully built ([a-f0-9]+)/.exec(stdout);
        imageId = imageIdMatch ? imageIdMatch[1] : undefined;
    }
    // Handle push if required
    let repoDigest;
    let finalImageRef = imageRef;
    if (props.registry && !props.skipPush) {
        const pushedImage = await pushImageToRegistry(imageRef, props.registry);
        finalImageRef = pushedImage.imageRef;
        repoDigest = pushedImage.repoDigest;
    }
    return {
        kind: "Image",
        tag,
        name,
        imageRef: finalImageRef,
        imageId,
        repoDigest,
        builtAt: Date.now(),
        build: props.build,
    };
});
//# sourceMappingURL=image.js.map