import { gatewayUrl, withAuthHeaders } from '~/lib/server/gateway';

/**
 * Admin API proxy endpoint.
 * Allows frontend code to call `/api/admin/*` while forwarding to Rust gateway `/api/admin/*`.
 */
export async function GET({ request, params }: { request: Request; params: any }) {
  return proxyRequest('GET', request, params);
}

export async function POST({ request, params }: { request: Request; params: any }) {
  return proxyRequest('POST', request, params);
}

export async function PUT({ request, params }: { request: Request; params: any }) {
  return proxyRequest('PUT', request, params);
}

export async function DELETE({ request, params }: { request: Request; params: any }) {
  return proxyRequest('DELETE', request, params);
}

export async function PATCH({ request, params }: { request: Request; params: any }) {
  return proxyRequest('PATCH', request, params);
}

const RETRYABLE_STATUSES = new Set([500, 502, 503, 504]);

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

async function fetchWithRetry(
  url: string,
  init: RequestInit,
  options: { retries?: number; retryDelayMs?: number } = {},
): Promise<Response> {
  const retries = Math.max(0, options.retries ?? 2);
  const retryDelayMs = Math.max(0, options.retryDelayMs ?? 250);

  let lastResponse: Response | null = null;
  let lastError: unknown = null;

  for (let attempt = 0; attempt <= retries; attempt += 1) {
    try {
      const response = await fetch(url, init);
      if (!RETRYABLE_STATUSES.has(response.status) || attempt === retries) {
        return response;
      }
      lastResponse = response;
    } catch (error) {
      lastError = error;
      if (attempt === retries) {
        throw error;
      }
    }

    await sleep(retryDelayMs * (attempt + 1));
  }

  if (lastResponse) return lastResponse;
  if (lastError) throw lastError;
  throw new Error('Gateway request failed');
}

async function proxyRequest(method: string, request: Request, params: any) {
  try {
    const pathParts = Array.isArray(params?.path)
      ? params.path
      : (params?.path ? [params.path] : []);
    const rawPath = pathParts.map((p: unknown) => String(p || '').trim()).filter(Boolean).join('/');
    const path = `/api/admin${rawPath ? `/${rawPath}` : ''}`;
    const url = new URL(request.url);
    const queryString = url.search ? url.search : '';

    let body: string | undefined;
    if (['POST', 'PUT', 'PATCH'].includes(method)) {
      body = await request.text();
    }

    const upstreamUrl = gatewayUrl(path + queryString);
    const upstreamInit: RequestInit = {
      method,
      headers: withAuthHeaders(request, {
        'Content-Type': request.headers.get('Content-Type') || 'application/json',
      }),
      body,
      cache: 'no-store',
    };

    const response = (method === 'GET')
      ? await fetchWithRetry(upstreamUrl, upstreamInit, { retries: 2, retryDelayMs: 250 })
      : await fetch(upstreamUrl, upstreamInit);
    const responseHeaders = new Headers();
    response.headers.forEach((value, key) => {
      if (!['server', 'transfer-encoding', 'connection'].includes(key.toLowerCase())) {
        responseHeaders.set(key, value);
      }
    });

    const responseBody = await response.text();
    return new Response(responseBody, {
      status: response.status,
      statusText: response.statusText,
      headers: responseHeaders,
    });
  } catch (error: any) {
    return new Response(
      JSON.stringify({ success: false, error: error?.message || 'Upstream gateway unavailable' }),
      { status: 502, headers: { 'Content-Type': 'application/json' } },
    );
  }
}
