import { Resource } from "../resource.js";
import { CloudflareApiError, handleApiError } from "./api-error.js";
import { createCloudflareApi, } from "./api.js";
/**
 * Creates a consumer for a Cloudflare Queue that processes messages using a Worker.
 *
 * @example
 * // Create a queue consumer with default settings
 * const queue = await Queue("notifications", {
 *   name: "notifications"
 * });
 *
 * const consumer = await QueueConsumer("notification-processor", {
 *   queue,
 *   scriptName: "notification-worker"
 * });
 *
 * @example
 * // Create a consumer with custom settings
 * const batchConsumer = await QueueConsumer("batch-processor", {
 *   queue,
 *   scriptName: "batch-worker",
 *   settings: {
 *     batchSize: 50,         // Process 50 messages at once
 *     maxConcurrency: 10,    // Allow 10 concurrent invocations
 *     maxRetries: 5,         // Retry failed messages up to 5 times
 *     maxWaitTimeMs: 2000,   // Wait up to 2 seconds to fill a batch
 *     retryDelay: 60         // Wait 60 seconds before retrying failed messages
 *   }
 * });
 *
 * @see https://developers.cloudflare.com/queues/platform/consumers/
 */
export const QueueConsumer = Resource("cloudflare::QueueConsumer", async function (_id, props) {
    // Get queueId from either props.queue or props.queueId
    const queueId = typeof props.queue === "string" ? props.queue : props.queue.id;
    if (this.scope.local && props.dev) {
        return {
            id: this.output?.id ?? "",
            queueId,
            queue: props.queue,
            type: "worker",
            scriptName: props.scriptName,
            settings: props.settings,
            accountId: this.output?.accountId ?? "",
        };
    }
    const api = await createCloudflareApi(props);
    if (this.phase === "delete") {
        if (props.delete !== false && this.output?.id) {
            // Delete the consumer
            await deleteQueueConsumer(api, queueId, this.output.id);
        }
        // Return void (a deleted consumer has no content)
        return this.destroy();
    }
    if (!queueId) {
        throw new Error("Either queue or queueId must be provided");
    }
    let consumerData;
    if (this.phase === "create" || !this.output?.id) {
        try {
            consumerData = await createQueueConsumer(api, queueId, props);
        }
        catch (err) {
            if (err instanceof CloudflareApiError &&
                err.status === 400 &&
                err.message.includes("already has a consumer") &&
                (props.adopt ?? this.scope.adopt)) {
                const consumerId = await findQueueConsumerId(api, props.scriptName, queueId);
                if (!consumerId) {
                    throw new Error(`Consumer for worker ${props.scriptName} and queue ${queueId} not found`);
                }
                consumerData = await updateQueueConsumer(api, queueId, consumerId, props);
            }
            else {
                throw err;
            }
        }
    }
    else {
        consumerData = await updateQueueConsumer(api, queueId, this.output.id, props);
    }
    const deadLetterQueue = props.settings?.deadLetterQueue
        ? typeof props.settings.deadLetterQueue === "string"
            ? props.settings.deadLetterQueue
            : props.settings.deadLetterQueue.name
        : undefined;
    return {
        id: consumerData.result.consumer_id,
        queueId,
        queue: props.queue,
        type: "worker",
        scriptName: props.scriptName,
        settings: consumerData.result.settings
            ? {
                batchSize: consumerData.result.settings.batch_size,
                maxConcurrency: consumerData.result.settings.max_concurrency,
                maxRetries: consumerData.result.settings.max_retries,
                maxWaitTimeMs: consumerData.result.settings.max_wait_time_ms,
                retryDelay: consumerData.result.settings.retry_delay,
                deadLetterQueue,
            }
            : props.settings
                ? {
                    ...props.settings,
                    deadLetterQueue,
                }
                : undefined,
        createdOn: consumerData.result.created_on,
        accountId: api.accountId,
    };
});
/**
 * Create a new Queue Consumer
 */
export async function createQueueConsumer(api, queueId, props) {
    // Prepare the create payload
    const createPayload = {
        script_name: props.scriptName,
        type: "worker",
    };
    // Add settings if provided
    if (props.settings) {
        createPayload.settings = {};
        if (props.settings.batchSize !== undefined) {
            createPayload.settings.batch_size = props.settings.batchSize;
        }
        if (props.settings.maxConcurrency !== undefined) {
            createPayload.settings.max_concurrency = props.settings.maxConcurrency;
        }
        if (props.settings.maxRetries !== undefined) {
            createPayload.settings.max_retries = props.settings.maxRetries;
        }
        if (props.settings.maxWaitTimeMs !== undefined) {
            createPayload.settings.max_wait_time_ms = props.settings.maxWaitTimeMs;
        }
        if (props.settings.retryDelay !== undefined) {
            createPayload.settings.retry_delay = props.settings.retryDelay;
        }
        if (props.settings.deadLetterQueue !== undefined) {
            const dlqName = typeof props.settings.deadLetterQueue === "string"
                ? props.settings.deadLetterQueue
                : props.settings.deadLetterQueue.name;
            createPayload.dead_letter_queue = dlqName;
        }
    }
    const createResponse = await api.post(`/accounts/${api.accountId}/queues/${queueId}/consumers`, createPayload);
    if (!createResponse.ok) {
        return await handleApiError(createResponse, "creating", "Queue Consumer", `for queue ${queueId}`);
    }
    return (await createResponse.json());
}
/**
 * Delete a Queue Consumer
 */
export async function deleteQueueConsumer(api, queueId, consumerId) {
    const deleteResponse = await api.delete(`/accounts/${api.accountId}/queues/${queueId}/consumers/${consumerId}`);
    if (!deleteResponse.ok && deleteResponse.status !== 404) {
        await handleApiError(deleteResponse, "deleting", "Queue Consumer", consumerId);
    }
}
/**
 * Update a Queue Consumer
 */
async function updateQueueConsumer(api, queueId, consumerId, props) {
    // Prepare the update payload
    const updatePayload = {
        script_name: props.scriptName,
        type: "worker",
    };
    // Add settings if provided
    if (props.settings) {
        updatePayload.settings = {};
        if (props.settings.batchSize !== undefined) {
            updatePayload.settings.batch_size = props.settings.batchSize;
        }
        if (props.settings.maxConcurrency !== undefined) {
            updatePayload.settings.max_concurrency = props.settings.maxConcurrency;
        }
        if (props.settings.maxRetries !== undefined) {
            updatePayload.settings.max_retries = props.settings.maxRetries;
        }
        if (props.settings.maxWaitTimeMs !== undefined) {
            updatePayload.settings.max_wait_time_ms = props.settings.maxWaitTimeMs;
        }
        if (props.settings.retryDelay !== undefined) {
            updatePayload.settings.retry_delay = props.settings.retryDelay;
        }
        if (props.settings.deadLetterQueue !== undefined) {
            const dlqName = typeof props.settings.deadLetterQueue === "string"
                ? props.settings.deadLetterQueue
                : props.settings.deadLetterQueue.name;
            updatePayload.dead_letter_queue = dlqName;
        }
    }
    // Use PUT to update the consumer
    const updateResponse = await api.put(`/accounts/${api.accountId}/queues/${queueId}/consumers/${consumerId}`, updatePayload);
    if (!updateResponse.ok) {
        return await handleApiError(updateResponse, "updating", "Queue Consumer", consumerId);
    }
    return (await updateResponse.json());
}
/**
 * List all consumers for a queue
 */
export async function listQueueConsumers(api, queueId) {
    const response = await api.get(`/accounts/${api.accountId}/queues/${queueId}/consumers`);
    if (!response.ok) {
        throw new CloudflareApiError(`Failed to list queue consumers: ${response.statusText}`, response);
    }
    const data = (await response.json());
    if (!data.success) {
        const errorMessage = data.errors?.[0]?.message || "Unknown error";
        throw new Error(`Failed to list queue consumers: ${errorMessage}`);
    }
    // Transform API response
    return (data.result || []).map((consumer) => ({
        id: consumer.consumer_id,
        scriptName: consumer.script,
        queueId: consumer.queue_id,
        queueName: consumer.queue_name,
        createdOn: consumer.created_on,
        settings: consumer.settings
            ? {
                batchSize: consumer.settings.batch_size,
                maxConcurrency: consumer.settings.max_concurrency,
                maxRetries: consumer.settings.max_retries,
                maxWaitTimeMs: consumer.settings.max_wait_time_ms,
                retryDelay: consumer.settings.retry_delay,
                deadLetterQueue: consumer.dead_letter_queue && consumer.dead_letter_queue !== ""
                    ? consumer.dead_letter_queue
                    : undefined,
            }
            : undefined,
    }));
}
export async function findQueueConsumerId(api, workerName, queueId) {
    const consumers = await listQueueConsumersForWorker(api, workerName);
    const consumer = consumers.find((c) => c.queueId === queueId);
    return consumer?.consumerId;
}
export async function listQueueConsumersForWorker(api, workerName) {
    const response = await api.get(`/accounts/${api.accountId}/workers/scripts/${workerName}/queue-consumers?perPage=100`);
    if (response.status === 404) {
        return [];
    }
    if (!response.ok) {
        return await handleApiError(response, "list", "QueueConsumer", `for worker ${workerName}`);
    }
    const data = (await response.json());
    return data.result.map((consumer) => ({
        queueName: consumer.queue_name,
        queueId: consumer.queue_id,
        consumerId: consumer.consumer_id,
        createdOn: consumer.created_on,
        settings: consumer.settings
            ? {
                ...consumer.settings,
                deadLetterQueue: consumer.dead_letter_queue,
            }
            : consumer.dead_letter_queue
                ? { deadLetterQueue: consumer.dead_letter_queue }
                : undefined,
    }));
}
//# sourceMappingURL=queue-consumer.js.map