import { composeServices } from '../core/app.js';
import { createHttpApp } from '../mcp-server/transports/http/httpTransport.js';
import { logger } from '../utils/internal/logger.js';
import { requestContextService } from '../utils/internal/requestContext.js';
/** Core string bindings injected into process.env for config parsing. */
const CORE_ENV_BINDINGS = [
    ['ENVIRONMENT', 'NODE_ENV'],
    ['LOG_LEVEL', 'MCP_LOG_LEVEL'],
    ['MCP_AUTH_MODE', 'MCP_AUTH_MODE'],
    ['MCP_AUTH_SECRET_KEY', 'MCP_AUTH_SECRET_KEY'],
    ['MCP_PUBLIC_URL', 'MCP_PUBLIC_URL'],
    ['OPENROUTER_API_KEY', 'OPENROUTER_API_KEY'],
    ['SUPABASE_URL', 'SUPABASE_URL'],
    ['SUPABASE_ANON_KEY', 'SUPABASE_ANON_KEY'],
    ['SUPABASE_SERVICE_ROLE_KEY', 'SUPABASE_SERVICE_ROLE_KEY'],
    ['STORAGE_PROVIDER_TYPE', 'STORAGE_PROVIDER_TYPE'],
    ['CANVAS_PROVIDER_TYPE', 'CANVAS_PROVIDER_TYPE'],
    ['OAUTH_ISSUER_URL', 'OAUTH_ISSUER_URL'],
    ['OAUTH_AUDIENCE', 'OAUTH_AUDIENCE'],
    ['OAUTH_JWKS_URI', 'OAUTH_JWKS_URI'],
    ['MCP_ALLOWED_ORIGINS', 'MCP_ALLOWED_ORIGINS'],
    ['SPEECH_TTS_ENABLED', 'SPEECH_TTS_ENABLED'],
    ['SPEECH_TTS_API_KEY', 'SPEECH_TTS_API_KEY'],
    ['SPEECH_STT_ENABLED', 'SPEECH_STT_ENABLED'],
    ['SPEECH_STT_API_KEY', 'SPEECH_STT_API_KEY'],
    ['OTEL_ENABLED', 'OTEL_ENABLED'],
    ['OTEL_EXPORTER_OTLP_TRACES_ENDPOINT', 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT'],
    ['OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT'],
];
/** Core object bindings stored on globalThis for storage/AI providers. */
const CORE_OBJECT_BINDINGS = [
    ['KV_NAMESPACE', 'KV_NAMESPACE'],
    ['R2_BUCKET', 'R2_BUCKET'],
    ['DB', 'DB'],
    ['AI', 'AI'],
];
function injectEnvVars(env, extraBindings) {
    if (typeof process === 'undefined')
        return;
    for (const [bindingKey, processKey] of CORE_ENV_BINDINGS) {
        const value = env[bindingKey];
        if (typeof value === 'string' && value.trim() !== '') {
            process.env[processKey] = value;
        }
    }
    if (extraBindings) {
        for (const [bindingKey, processKey] of extraBindings) {
            const value = env[bindingKey];
            if (typeof value === 'string' && value.trim() !== '') {
                process.env[processKey] = value;
            }
        }
    }
}
function storeBindings(env, extraBindings) {
    for (const [bindingKey, globalKey] of CORE_OBJECT_BINDINGS) {
        const value = env[bindingKey];
        if (value != null) {
            Object.assign(globalThis, { [globalKey]: value });
        }
    }
    if (extraBindings) {
        for (const [bindingKey, globalKey] of extraBindings) {
            const value = env[bindingKey];
            if (value != null) {
                Object.assign(globalThis, { [globalKey]: value });
            }
        }
    }
}
/**
 * Returns a standard Cloudflare Workers export object (`{ fetch, scheduled }`).
 * Handles env injection, binding storage, singleton init caching, per-request
 * server creation, and error responses.
 */
export function createWorkerHandler(options = {}) {
    const { extraEnvBindings, extraObjectBindings, instructions: instructionsOption, onScheduled, ...appOptions } = options;
    let appPromise = null;
    function initializeApp(env) {
        if (appPromise)
            return appPromise;
        appPromise = (async () => {
            const initStartTime = Date.now();
            try {
                if (typeof process !== 'undefined' && process.env) {
                    process.env.IS_SERVERLESS = 'true';
                    process.env.MCP_TRANSPORT_TYPE = 'http'; // Workers are always HTTP — context.ts reads this for tenant isolation
                }
                else {
                    Object.assign(globalThis, { IS_SERVERLESS: true });
                }
                const resolvedInstructions = typeof instructionsOption === 'function' ? instructionsOption(env) : instructionsOption;
                const { createServer, manifest } = await composeServices({
                    ...appOptions,
                    ...(resolvedInstructions && { instructions: resolvedInstructions }),
                });
                const logLevel = env.LOG_LEVEL?.toLowerCase() ?? 'info';
                const validLogLevels = [
                    'debug',
                    'info',
                    'notice',
                    'warning',
                    'error',
                    'crit',
                    'alert',
                    'emerg',
                ];
                const validatedLogLevel = validLogLevels.includes(logLevel)
                    ? logLevel
                    : 'info';
                await logger.initialize(validatedLogLevel, 'http');
                const workerContext = requestContextService.createRequestContext({
                    operation: 'WorkerInitialization',
                    isServerless: true,
                });
                logger.info('Cloudflare Worker initializing...', {
                    ...workerContext,
                    environment: env.ENVIRONMENT ?? 'production',
                    storageProvider: env.STORAGE_PROVIDER_TYPE ?? 'in-memory',
                });
                const { app } = await createHttpApp(createServer, workerContext, manifest);
                const initDuration = Date.now() - initStartTime;
                logger.info('Cloudflare Worker initialized successfully.', {
                    ...workerContext,
                    initDurationMs: initDuration,
                });
                return app;
            }
            catch (error) {
                const initDuration = Date.now() - initStartTime;
                const errorContext = requestContextService.createRequestContext({
                    operation: 'WorkerInitialization',
                    isServerless: true,
                    initDurationMs: initDuration,
                    error: error instanceof Error ? error.message : String(error),
                    stack: error instanceof Error ? error.stack : undefined,
                });
                logger.crit('Failed to initialize Cloudflare Worker.', error instanceof Error ? error : new Error(String(error)), errorContext);
                appPromise = null;
                throw error;
            }
        })();
        return appPromise;
    }
    return {
        async fetch(request, env, ctx) {
            try {
                injectEnvVars(env, extraEnvBindings);
                storeBindings(env, extraObjectBindings);
                const app = await initializeApp(env);
                const cfProperties = request.cf;
                const requestId = request.headers.get('cf-ray') ?? crypto.randomUUID();
                const requestContext = requestContextService.createRequestContext({
                    operation: 'WorkerFetch',
                    requestId,
                    isServerless: true,
                    ...(cfProperties && {
                        colo: cfProperties.colo,
                        country: cfProperties.country,
                        city: cfProperties.city,
                    }),
                });
                logger.debug('Processing Worker fetch request.', {
                    ...requestContext,
                    method: request.method,
                    url: request.url,
                    colo: cfProperties?.colo,
                });
                return await app.fetch(request, env, ctx);
            }
            catch (error) {
                const requestId = request.headers.get('cf-ray');
                const errorContext = requestContextService.createRequestContext({
                    operation: 'WorkerFetch',
                    isServerless: true,
                    method: request.method,
                    url: request.url,
                    ...(requestId && { requestId }),
                });
                logger.error('Worker fetch handler error.', error instanceof Error ? error : new Error(String(error)), errorContext);
                return new Response(JSON.stringify({
                    error: 'Internal Server Error',
                    message: 'An internal error occurred.',
                }), {
                    status: 500,
                    headers: { 'Content-Type': 'application/json' },
                });
            }
        },
        async scheduled(controller, env, ctx) {
            try {
                injectEnvVars(env, extraEnvBindings);
                storeBindings(env, extraObjectBindings);
                await initializeApp(env);
                if (onScheduled) {
                    await onScheduled(controller, env, ctx);
                    return;
                }
                const scheduledContext = requestContextService.createRequestContext({
                    operation: 'WorkerScheduled',
                    isServerless: true,
                    cron: controller.cron,
                });
                logger.info('Processing scheduled event.', {
                    ...scheduledContext,
                    scheduledTime: new Date(controller.scheduledTime).toISOString(),
                });
                logger.info('Scheduled event completed.', scheduledContext);
            }
            catch (error) {
                const errorContext = requestContextService.createRequestContext({
                    operation: 'WorkerScheduled',
                    isServerless: true,
                    cron: controller.cron,
                });
                logger.error('Worker scheduled handler error.', error instanceof Error ? error : new Error(String(error)), errorContext);
            }
        },
    };
}
//# sourceMappingURL=worker.js.map