const quote = (value) => JSON.stringify(value);
const START_MODULE_PLACEHOLDER = '__ZINTRUST_START_MODULE__';
const injectStartModuleSpecifier = (template, startModuleSpecifier) => {
    return template.replaceAll(START_MODULE_PLACEHOLDER, quote(startModuleSpecifier));
};
const denoRunnerTemplate = [
    "import http from 'node:http';",
    `import { deno } from ${START_MODULE_PLACEHOLDER};`,
    '',
    "const port = Number.parseInt(process.env.PORT ?? '3000', 10) || 3000;",
    "const host = process.env.HOST ?? 'localhost';",
    '',
    'const readBody = async (req: http.IncomingMessage): Promise<Buffer | undefined> => {',
    "  if (req.method === 'GET' || req.method === 'HEAD') return undefined;",
    '  const chunks: Buffer[] = [];',
    '  for await (const chunk of req) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));',
    '  return chunks.length > 0 ? Buffer.concat(chunks) : undefined;',
    '};',
    '',
    'const server = http.createServer(async (req, res) => {',
    '  try {',
    "    const proto = (req.headers['x-forwarded-proto'] ?? 'http').toString();",
    '    const authority = (req.headers.host ?? host).toString();',
    "    const url = new URL(req.url ?? '/', proto + '://' + authority);",
    '',
    '    const headers = new Headers();',
    '    for (const [key, value] of Object.entries(req.headers)) {',
    '      if (value === undefined) continue;',
    '      if (Array.isArray(value)) {',
    '        for (const v of value) headers.append(key, v);',
    '      } else {',
    '        headers.set(key, String(value));',
    '      }',
    '    }',
    '',
    '    const body = await readBody(req);',
    '    const request = new Request(url.toString(), {',
    "      method: req.method ?? 'GET',",
    '      headers,',
    '      body,',
    '    });',
    '',
    '    const response = await deno(request);',
    '',
    '    res.statusCode = response.status;',
    '    response.headers.forEach((v, k) => res.setHeader(k, v));',
    '',
    '    const ab = await response.arrayBuffer();',
    '    res.end(Buffer.from(ab));',
    '  } catch (err) {',
    '    res.statusCode = 500;',
    "    res.setHeader('content-type', 'text/plain');",
    "    res.end('Internal Server Error' + (err as Error).message);",
    '  }',
    '});',
    '',
    'server.listen(port, host, () => {',
    '  // eslint-disable-next-line no-console',
    "  console.log('Deno adapter server listening at http://' + host + ':' + port);",
    '});',
    '',
].join('\n');
const lambdaRunnerTemplate = [
    "import http from 'node:http';",
    `import { handler as lambdaHandler } from ${START_MODULE_PLACEHOLDER};`,
    '',
    "const port = Number.parseInt(process.env.PORT ?? '3000', 10) || 3000;",
    "const host = process.env.HOST ?? 'localhost';",
    '',
    'const readBody = async (req: http.IncomingMessage): Promise<string | undefined> => {',
    "  if (req.method === 'GET' || req.method === 'HEAD') return undefined;",
    '  const chunks: Buffer[] = [];',
    '  for await (const chunk of req) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));',
    "  return chunks.length > 0 ? Buffer.concat(chunks).toString('utf-8') : undefined;",
    '};',
    '',
    'const server = http.createServer(async (req, res) => {',
    '  try {',
    "    const proto = (req.headers['x-forwarded-proto'] ?? 'http').toString();",
    '    const authority = (req.headers.host ?? host).toString();',
    "    const url = new URL(req.url ?? '/', proto + '://' + authority);",
    '',
    '    const body = await readBody(req);',
    '    const headers: Record<string, string> = {};',
    '    for (const [k, v] of Object.entries(req.headers)) {',
    '      if (v === undefined) continue;',
    "      headers[k] = Array.isArray(v) ? v.join(',') : String(v);",
    '    }',
    '',
    '    const queryStringParameters: Record<string, string> = {};',
    '    url.searchParams.forEach((value, key) => {',
    '      if (queryStringParameters[key] === undefined) queryStringParameters[key] = value;',
    '    });',
    '',
    '    const event = {',
    "      version: '2.0',",
    "      routeKey: '$default',",
    '      rawPath: url.pathname,',
    '      rawQueryString: url.searchParams.toString(),',
    '      headers,',
    '      queryStringParameters,',
    '      requestContext: {',
    '        http: {',
    "          method: req.method ?? 'GET',",
    '          path: url.pathname,',
    "          sourceIp: (req.socket.remoteAddress ?? '').toString(),",
    '        },',
    '      },',
    '      body: body ?? null,',
    '      isBase64Encoded: false,',
    '    };',
    '',
    '    const result = (await lambdaHandler(event, {})) as {',
    '      statusCode?: number;',
    '      headers?: Record<string, string | string[]>;',
    '      body?: string;',
    '      isBase64Encoded?: boolean;',
    '    };',
    '',
    '    res.statusCode = typeof result.statusCode === "number" ? result.statusCode : 200;',
    '    if (result.headers) {',
    '      for (const [k, v] of Object.entries(result.headers)) {',
    '        res.setHeader(k, v as any);',
    '      }',
    '    }',
    '',
    '    if (result.isBase64Encoded === true && typeof result.body === "string") {',
    "      res.end(Buffer.from(result.body, 'base64'));",
    '    } else {',
    "      res.end(result.body ?? '');",
    '    }',
    '  } catch {',
    '    res.statusCode = 500;',
    "    res.setHeader('content-type', 'application/json');",
    "    res.end(JSON.stringify({ message: 'Internal Server Error' }));",
    '  }',
    '});',
    '',
    'server.listen(port, host, () => {',
    '  // eslint-disable-next-line no-console',
    "  console.log('Lambda adapter server listening at http://' + host + ':' + port);",
    '});',
    '',
].join('\n');
export const createDenoRunnerSource = (startModuleSpecifier) => {
    return injectStartModuleSpecifier(denoRunnerTemplate, startModuleSpecifier);
};
export const createLambdaRunnerSource = (startModuleSpecifier) => {
    return injectStartModuleSpecifier(lambdaRunnerTemplate, startModuleSpecifier);
};
