import { Resource, ResourceKind } from "../resource.js";
import { logger } from "../util/logger.js";
import { CloudflareApiError, handleApiError } from "./api-error.js";
import { createCloudflareApi, } from "./api.js";
export function isDispatchNamespace(resource) {
    return resource?.[ResourceKind] === "cloudflare::DispatchNamespace";
}
/**
 * A Cloudflare Dispatch Namespace enables routing worker requests to different scripts based on patterns.
 *
 * @see https://developers.cloudflare.com/workers/configuration/routing/dispatch-namespace/
 *
 * @example
 * // Create a basic dispatch namespace
 * const myNamespace = await DispatchNamespace("my-namespace", {
 *   namespace: "my-namespace"
 * });
 *
 * @example
 * // Create dispatch namespace with default name from id
 * const dispatchNS = await DispatchNamespace("api-dispatch");
 *
 * @example
 * // Adopt an existing namespace if it already exists instead of failing
 * const existingNamespace = await DispatchNamespace("existing-ns", {
 *   namespace: "existing-namespace",
 *   adopt: true
 * });
 *
 * @example
 * // When removing from Alchemy state, keep the namespace in Cloudflare
 * const preservedNamespace = await DispatchNamespace("preserve-ns", {
 *   namespace: "preserved-namespace",
 *   delete: false
 * });
 */
export const DispatchNamespace = Resource("cloudflare::DispatchNamespace", async function (id, props = {}) {
    // Create Cloudflare API client with automatic account discovery
    const api = await createCloudflareApi(props);
    const namespace = props.namespace ??
        this.output?.namespace ??
        this.scope.createPhysicalName(id);
    const adopt = props.adopt ?? this.scope.adopt;
    if (this.phase === "delete") {
        // For delete operations, we need to check if the namespace exists in the output
        const namespaceName = this.output?.namespace;
        if (namespaceName && props.delete !== false) {
            await deleteDispatchNamespace(api, namespaceName);
        }
        // Return minimal output for deleted state
        return this.destroy();
    }
    // For create or update operations
    let createdAt = this.phase === "update"
        ? this.output?.createdAt || Date.now()
        : Date.now();
    if (this.phase === "update") {
        if (this.output.namespace !== namespace) {
            this.replace();
        }
        // For updates, just refresh metadata
    }
    else {
        try {
            // Try to create the dispatch namespace
            await createDispatchNamespace(api, {
                ...props,
                namespace,
            });
            createdAt = Date.now();
        }
        catch (error) {
            // Check if this is a "namespace already exists" error and adopt is enabled
            if (adopt &&
                error instanceof CloudflareApiError &&
                error.status === 400 &&
                (error.message.includes("already exists") ||
                    error.message.includes("Ensure it does not already exist"))) {
                logger.log(`Dispatch namespace '${namespace}' already exists, adopting it`);
                // Get the namespace to retrieve ID and validate it exists
                const existingNamespace = await getDispatchNamespace(api, namespace);
                if (!existingNamespace) {
                    throw new Error(`Failed to find existing dispatch namespace '${namespace}'`);
                }
            }
            else {
                // Re-throw the error if adopt is false or it's not a "namespace already exists" error
                throw error;
            }
        }
    }
    // Get the namespace information after creation/adoption
    const namespaceInfo = await getDispatchNamespace(api, namespace);
    if (!namespaceInfo) {
        throw new Error(`Failed to get namespace information for '${namespace}'`);
    }
    return {
        type: "dispatch_namespace",
        namespace,
        namespaceName: namespaceInfo.namespaceName,
        namespaceId: namespaceInfo.namespaceId,
        createdAt: createdAt,
        modifiedAt: Date.now(),
    };
});
export async function createDispatchNamespace(api, props) {
    const createResponse = await api.post(`/accounts/${api.accountId}/workers/dispatch/namespaces`, {
        name: props.namespace,
    });
    if (!createResponse.ok) {
        await handleApiError(createResponse, "create", "dispatch_namespace", props.namespace);
    }
}
export async function getDispatchNamespace(api, namespace) {
    const getResponse = await api.get(`/accounts/${api.accountId}/workers/dispatch/namespaces/${namespace}`);
    if (getResponse.status === 404) {
        return undefined;
    }
    if (!getResponse.ok) {
        await handleApiError(getResponse, "get", "dispatch_namespace", namespace);
    }
    const result = (await getResponse.json());
    return {
        namespaceName: result.result.namespace_name,
        namespaceId: result.result.namespace_id,
    };
}
export async function deleteDispatchNamespace(api, namespace) {
    // Delete dispatch namespace
    const deleteResponse = await api.delete(`/accounts/${api.accountId}/workers/dispatch/namespaces/${namespace}`);
    if (!deleteResponse.ok && deleteResponse.status !== 404) {
        await handleApiError(deleteResponse, "delete", "dispatch_namespace", namespace);
    }
}
export async function listWorkersInNamespace(api, namespace) {
    const response = await api.get(`/accounts/${api.accountId}/workers/dispatch/namespaces/${namespace}/scripts`);
    if (!response.ok) {
        await handleApiError(response, "list workers in", "dispatch_namespace", namespace);
    }
    const data = (await response.json());
    return data.result || [];
}
//# sourceMappingURL=dispatch-namespace.js.map