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, isRecord, isUserId, USER_PARENT_FIELDS } from './users';
import { canFilterBvas } from './bvasInfo';
import {
  MAX_VOTER_IMAGE_SIZE, isRegisteredVoter, isRegisteredVoterPage, validVoterCount, voterImageType,
} from './registeredVoters';

function json(body: unknown, status = 200) {
  return NextResponse.json(body, { status, headers: { 'Cache-Control': 'private, no-store' } });
}

export async function proxyRegisteredVoters(request: NextRequest, id?: string, image = false) {
  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 access registered voters.' }, 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' && !canManageUsers(user)) return json({ error: 'Only super admins can delete registered-voter records.' }, 403);
    if (request.method !== 'GET' && isCrossOriginRequest(request)) {
      return json({ error: 'Cross-origin requests are not allowed.' }, 403);
    }
    if (id !== undefined && !/^[a-zA-Z0-9_-]{1,128}$/.test(id)) return json({ error: 'Invalid registered-voter ID.' }, 422);
    const query = request.nextUrl.searchParams;
    if (!canFilterBvas(user) && USER_PARENT_FIELDS.some((field) => query.has(field))) {
      return json({ error: 'Only super admins and national administrators can filter geography.' }, 403);
    }
    for (const [key, value] of Array.from(query.entries())) {
      const geography = USER_PARENT_FIELDS.some((field) => field === key);
      if (id !== undefined || request.method !== 'GET' || !['page', 'per_page', ...USER_PARENT_FIELDS].includes(key) || query.getAll(key).length !== 1 ||
          (geography ? !isUserId(value) : !/^[1-9]\d*$/.test(value) || !Number.isSafeInteger(Number(value)) || (key === 'per_page' && Number(value) > 100))) {
        return json({ error: 'Invalid registered-voter filters.' }, 422);
      }
    }
    let body: FormData | undefined;
    if (request.method === 'POST') {
      let form: FormData;
      try { form = await request.formData(); }
      catch { return json({ error: 'Submit the count, note, and image as form data.' }, 400); }
      const errors: Record<string, string[]> = {};
      for (const key of Array.from(form.keys())) {
        if (!['numbers', 'note', 'image'].includes(key) || form.getAll(key).length !== 1) errors[key] = ['Unsupported or duplicate field.'];
      }
      const count = form.get('numbers');
      if (typeof count !== 'string' || !/^\d+$/.test(count) || !validVoterCount(Number(count))) errors.numbers = ['Enter a whole number from 0 to 4294967295.'];
      const note = form.get('note');
      if (note !== null && (typeof note !== 'string' || Array.from(note).length > 5000)) errors.note = ['Note must contain at most 5000 characters.'];
      const file = form.get('image');
      if (!(file instanceof File) || !file.size || file.size > MAX_VOTER_IMAGE_SIZE) errors.image = ['Choose an image file of at most 5120 KB.'];
      else if (!voterImageType(new Uint8Array(await file.arrayBuffer()))) errors.image = ['Choose a JPEG, PNG, GIF, or WebP image.'];
      if (Object.keys(errors).length) return json({ error: 'Check the registered-voter details.', errors }, 422);
      body = form;
    }
    const base = process.env.NEXT_PUBLIC_URL?.trim().replace(/\/+$/, '');
    if (!base) return json({ error: 'The registered-voters API base URL is not configured.' }, 503);
    let response: Response;
    try {
      response = await fetch(`${base}/v1/registered-voters${id ? `/${encodeURIComponent(id)}` : ''}${image ? '/image' : ''}${query.size ? `?${query}` : ''}`, {
        method: request.method, headers: { Accept: image ? 'text/plain, application/json' : 'application/json', Authorization: `Bearer ${token}` },
        body, cache: 'no-store', redirect: 'manual', signal: AbortSignal.timeout(30000),
      });
    } catch { return json({ error: 'Unable to reach the registered-voters service. Please try again.' }, 502); }
    if (response.ok && request.method === 'DELETE') return new NextResponse(null, { status: 204, headers: { 'Cache-Control': 'private, no-store' } });
    if (response.ok && image) {
      const text = (await response.text()).trim();
      let base64 = text;
      if (text.startsWith('"')) {
        try { base64 = JSON.parse(text); }
        catch { return json({ error: 'The image service returned invalid base64.' }, 502); }
      }
      if (typeof base64 !== 'string' || !base64 || base64.length > Math.ceil(MAX_VOTER_IMAGE_SIZE / 3) * 4 ||
          base64.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(base64)) {
        return json({ error: 'The image service returned invalid base64.' }, 502);
      }
      const bytes = Buffer.from(base64, 'base64');
      if (bytes.length > MAX_VOTER_IMAGE_SIZE || bytes.toString('base64') !== base64) return json({ error: 'The image service returned invalid base64.' }, 502);
      const type = voterImageType(bytes);
      if (!type) return json({ error: 'The image service returned an unsupported image.' }, 502);
      return new NextResponse(bytes, { headers: {
        'Content-Type': type, 'Cache-Control': 'private, no-store', 'X-Content-Type-Options': 'nosniff',
        'Content-Security-Policy': "default-src 'none'; sandbox",
      } });
    }
    let data: unknown;
    try { data = await response.json(); }
    catch { return json({ error: 'The registered-voters service returned an invalid response.' }, 502); }
    if (!response.ok) {
      const result = json({
        error: isRecord(data) && typeof data.message === 'string' ? data.message : 'The registered-voters request failed. Please try again.',
        ...(isRecord(data) && isRecord(data.errors) ? { errors: data.errors } : {}),
      }, response.status >= 400 && response.status < 500 ? response.status : 502);
      if (response.status === 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 === 'GET' && !id ? !isRegisteredVoterPage(data) : !isRecord(data) || !isRegisteredVoter(data.data)) {
      return json({ error: 'The registered-voters service returned invalid records.' }, 502);
    }
    return json(data, response.status);
  } catch (error) {
    console.error('Registered-voters request failed:', error);
    return json({ error: 'Unable to process the registered-voters request.' }, 500);
  }
}
