import { getEnvVariable, getNodeEnvironment } from '@hexclave/shared/dist/utils/env';
import './polyfills';

import { HexclaveAssertionError } from '@hexclave/shared/dist/utils/errors';
import { wait } from '@hexclave/shared/dist/utils/promises';
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';

const corsAllowedRequestHeaders = [
  // General
  'authorization',
  'content-type',
  'x-stack-project-id',
  'x-stack-override-error-status',
  'x-stack-random-nonce',  // used to forcefully disable some caches
  'x-stack-client-version',
  'x-stack-disable-artificial-development-delay',

  // Project auth
  'x-stack-request-type',
  'x-stack-publishable-client-key',
  'x-stack-secret-server-key',
  'x-stack-super-secret-admin-key',
  'x-stack-admin-access-token',

  // User auth
  'x-stack-refresh-token',
  'x-stack-access-token',
];

const corsAllowedResponseHeaders = [
  'content-type',
  'x-stack-actual-status',
  'x-stack-known-error',
];

// Hexclave rebrand: every `x-stack-*` header is dual-accepted under its `x-hexclave-*` equivalent.
// Derive the alias names so the CORS allowlists never drift.
function withHexclaveHeaderAliases(headers: string[]): string[] {
  return headers.flatMap((header) => header.startsWith('x-stack-')
    ? [header, `x-hexclave-${header.slice('x-stack-'.length)}`]
    : [header]);
}
const corsAllowedRequestHeadersWithAliases = withHexclaveHeaderAliases(corsAllowedRequestHeaders);
const corsAllowedResponseHeadersWithAliases = withHexclaveHeaderAliases(corsAllowedResponseHeaders);

export async function proxy(request: NextRequest) {
  const delay = Number.parseInt(getEnvVariable('STACK_ARTIFICIAL_DEVELOPMENT_DELAY_MS', '0'));
  if (delay) {
    if (getNodeEnvironment().includes('production')) {
      throw new HexclaveAssertionError('STACK_ARTIFICIAL_DEVELOPMENT_DELAY_MS is only allowed in development');
    }
    if (!request.headers.get('x-stack-disable-artificial-development-delay')) {
      await wait(delay);
    }
  }

  const url = new URL(request.url);
  const isApiRequest = url.pathname.startsWith('/api/');

  // Hexclave rebrand: dual-accept request headers — copy each `x-hexclave-*` onto its `x-stack-*`
  // equivalent so downstream API routes that read `x-stack-*` keep working unchanged. The new form
  // wins when both are present.
  const newRequestHeaders = new Headers(request.headers);
  for (const [name, value] of request.headers) {
    if (name.startsWith('x-hexclave-')) {
      newRequestHeaders.set(`x-stack-${name.slice('x-hexclave-'.length)}`, value);
    }
  }

  // default headers
  const responseInit = {
    request: {
      headers: newRequestHeaders,
    },
    headers: {
      // CORS headers
      ...(!isApiRequest ? {} : {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
        "Access-Control-Allow-Headers": corsAllowedRequestHeadersWithAliases.join(', '),
        "Access-Control-Expose-Headers": corsAllowedResponseHeadersWithAliases.join(', '),
      }),
    },
  };

  // we want to allow preflight requests to pass through
  // even if the API route does not implement OPTIONS
  if (request.method === 'OPTIONS' && isApiRequest) {
    return new Response(null, responseInit);
  }

  return NextResponse.next(responseInit);
}

export const config = {
  matcher: '/:path*',
};
