import 'server-only';
import { NextRequest, NextResponse } from 'next/server';
import { isCrossOriginRequest } from './sameOrigin';
import { BACKEND_TOKEN_COOKIE_NAME, SESSION_COOKIE_NAME, parseSessionToken } from './session';
import { canManageUsers, isManagedUser, isRecord, isUserId, isUserPage, validateUserPayload, validateUserQuery } from './users';

function json(body: unknown, status = 200) {
  return NextResponse.json(body, { status, headers: { 'Cache-Control': 'private, no-store' } });
}

export async function proxyUsers(request: NextRequest, userId?: string) {
  try {
    const token = request.cookies.get(BACKEND_TOKEN_COOKIE_NAME)?.value;
    const user = await parseSessionToken(request.cookies.get(SESSION_COOKIE_NAME)?.value, token);
    if (!user || !token) {
      const result = json({ error: 'Sign in to manage users.' }, 401);
      for (const name of [SESSION_COOKIE_NAME, BACKEND_TOKEN_COOKIE_NAME]) result.cookies.set(name, '', { httpOnly: true, path: '/', sameSite: 'lax', maxAge: 0 });
      return result;
    }
    if (!canManageUsers(user)) return json({ error: 'Only super admins can manage users.' }, 403);
    if (request.method !== 'GET' && isCrossOriginRequest(request)) {
      return json({ error: 'Cross-origin requests are not allowed.' }, 403);
    }
    const baseUrl = process.env.NEXT_PUBLIC_URL?.trim().replace(/\/+$/, '');
    if (!baseUrl) return json({ error: 'The users API base URL is not configured.' }, 503);
    const queryErrors = validateUserQuery(request.nextUrl.searchParams);
    if (Object.keys(queryErrors).length) return json({ error: 'Check your filters.', errors: queryErrors }, 422);
    if (userId !== undefined && !isUserId(userId)) {
      return json({ error: 'A valid user UUID is required.' }, 422);
    }

    let body: unknown;
    if (request.method !== 'GET') {
      try {
        body = await request.json();
      } catch {
        return json({ error: 'A valid JSON request body is required.' }, 400);
      }
      if (request.method === 'DELETE') {
        if (!userId || !isRecord(body) || body.confirmation !== 'delete') {
          return json({ error: 'Type delete to confirm deleting this user.' }, 422);
        }
        body = undefined;
      } else {
        const errors = validateUserPayload(body, request.method === 'PUT' ? 'update' : 'create');
        if (Object.keys(errors).length) return json({ error: 'Check the user details.', errors }, 422);
        if (request.method === 'PUT' && isRecord(body) && body.password === '') {
          const { password, ...details } = body;
          body = details;
        }
      }
    }

    const path = userId === undefined ? '' : `/${userId}`;
    const query = request.nextUrl.searchParams.toString();
    let response: Response;
    try {
      response = await fetch(`${baseUrl}/v1/users${path}${query ? `?${query}` : ''}`, {
        method: request.method,
        headers: {
          Accept: 'application/json', Authorization: `Bearer ${token}`,
          ...(body ? { 'Content-Type': 'application/json' } : {}),
        },
        ...(body ? { body: JSON.stringify(body) } : {}),
        cache: 'no-store',
        redirect: 'manual',
        signal: AbortSignal.timeout(15000),
      });
    } catch {
      return json({ error: 'Unable to reach the users service. Please try again.' }, 502);
    }

    if (response.status === 401) {
      const result = json({ error: 'Your session has expired. Sign in again.' }, 401);
      for (const name of [SESSION_COOKIE_NAME, BACKEND_TOKEN_COOKIE_NAME]) {
        result.cookies.set(name, '', { httpOnly: true, path: '/', sameSite: 'lax', maxAge: 0 });
      }
      return result;
    }
    if (request.method === 'DELETE' && response.ok) {
      return response.status === 204
        ? new NextResponse(null, { status: 204, headers: { 'Cache-Control': 'private, no-store' } })
        : json({ error: 'The users service did not confirm deletion. Refresh the list before retrying.' }, 502);
    }
    let data: unknown;
    try {
      data = await response.json();
    } catch {
      return json({ error: 'The users service returned an invalid response.' }, 502);
    }
    if (!response.ok) {
      const errors = isRecord(data) && isRecord(data.errors)
        ? Object.fromEntries(Object.entries(data.errors).filter(([, messages]) =>
          Array.isArray(messages) && messages.every((message) => typeof message === 'string')))
        : undefined;
      const message = isRecord(data) && typeof data.message === 'string' ? data.message
        : isRecord(data) && typeof data.error === 'string' ? data.error
          : response.status === 401 ? 'Your session has expired. Sign in again.'
            : response.status === 403 ? 'You do not have permission to perform this action.'
              : response.status === 404 ? 'This user could not be found.'
                : 'The users request failed. Please try again.';
      const result = json({ error: message, ...(errors ? { errors } : {}) },
        response.status >= 400 && response.status < 500 ? response.status : 502);
      return result;
    }
    if (request.method === 'GET' && userId === undefined) {
      if (!isUserPage(data)) return json({ error: 'The users service returned an invalid user list.' }, 502);
    } else if (!isRecord(data) || !isManagedUser(data.data)) {
      return json({ error: 'The users service returned invalid user details.' }, 502);
    }
    return json(data, response.status);
  } catch (error: unknown) {
    console.error('User management request failed:', error);
    return json({ error: 'Unable to process the users request. Please try again.' }, 500);
  }
}
