import { randomUUID } from 'node:crypto';
import { cookies } from 'next/headers';
import { NextRequest, NextResponse } from 'next/server';

const API = process.env.NEXT_PUBLIC_API_URL ?? 'http://127.0.0.1:3000';
const SESSION_COOKIE = 'mdv_session';
const COUNTRY_FALLBACK = 'ES';

const addressSchema = {
  type: 'object',
  required: ['line1', 'city', 'postalCode', 'country'],
  properties: {
    line1: { type: 'string', minLength: 1, maxLength: 200 },
    line2: { type: 'string', maxLength: 200 },
    city: { type: 'string', minLength: 1, maxLength: 80 },
    postalCode: { type: 'string', minLength: 1, maxLength: 20 },
    country: { type: 'string', minLength: 2, maxLength: 80 },
    firstName: { type: 'string', maxLength: 80 },
    lastName: { type: 'string', maxLength: 80 },
    phone: { type: 'string', maxLength: 40 },
    email: { type: 'string', maxLength: 160 },
  },
} as const;

const itemSchema = {
  type: 'object',
  required: ['productId', 'variantId', 'quantity'],
  properties: {
    productId: { type: 'string' },
    variantId: { type: 'string' },
    quantity: { type: 'number' },
  },
} as const;

const bodySchema = {
  type: 'object',
  required: ['shippingAddress', 'items'],
  properties: {
    shippingAddress: addressSchema,
    billingAddress: addressSchema,
    items: { type: 'array', items: itemSchema, minItems: 1 },
    promoCode: { type: 'string', maxLength: 64 },
    notes: { type: 'string', maxLength: 500 },
    idempotencyKey: { type: 'string', maxLength: 120 },
  },
} as const;

const UNAUTHORIZED = {
  error: {
    code: 'UNAUTHORIZED',
    message: 'Debes iniciar sesión para finalizar el pedido.',
  },
} as const;

interface RawItem {
  productId?: unknown;
  variantId?: unknown;
  quantity?: unknown;
}

interface RawBody {
  shippingAddress?: { country?: unknown; postalCode?: unknown; [key: string]: unknown };
  items?: RawItem[];
  promoCode?: string | null;
  idempotencyKey?: string;
}

function isNonEmptyString(value: unknown): value is string {
  return typeof value === 'string' && value.length > 0;
}

function isUuid(value: unknown): value is string {
  return typeof value === 'string' && /^[0-9a-f-]{36}$/i.test(value);
}

function parseQuantity(value: unknown): number {
  const number = Number(value);
  if (!Number.isFinite(number) || !Number.isInteger(number) || number < 1 || number > 99) {
    throw new Error('Cantidad inválida en el carrito.');
  }
  return number;
}

function parseItems(raw: RawItem[] | undefined): {
  productId: string;
  variantId: string;
  quantity: number;
}[] {
  if (!Array.isArray(raw) || raw.length === 0) {
    throw new Error('El carrito está vacío.');
  }
  return raw.map((item, index) => {
    if (!isUuid(item.productId)) throw new Error(`productId inválido (item ${index}).`);
    if (!isUuid(item.variantId)) throw new Error(`variantId inválido (item ${index}).`);
    return {
      productId: item.productId,
      variantId: item.variantId,
      quantity: parseQuantity(item.quantity),
    };
  });
}

async function syncCart(
  cookies: string,
  items: { productId: string; variantId: string; quantity: number }[],
): Promise<{ ok: true } | { ok: false; status: number; message: string }> {
  let serverItems: { variantId: string; quantity: number }[] = [];
  try {
    const current = await fetch(`${API}/cart`, {
      headers: { Cookie: cookies },
      cache: 'no-store',
    });
    if (current.ok) {
      const body = (await current.json()) as { items?: { variantId?: unknown; quantity?: unknown }[] };
      serverItems = (body.items ?? [])
        .filter(
          (entry): entry is { variantId: string; quantity: number } =>
            typeof entry.variantId === 'string' && typeof entry.quantity === 'number',
        )
        .map((entry) => ({ variantId: entry.variantId, quantity: entry.quantity }));
    }
  } catch {
    // Treat the cart as empty if the backend is unreachable; the checkout call
    // will surface the real problem.
  }

  const nextByVariant = new Map(items.map((item) => [item.variantId, item]));
  const operations: Promise<Response>[] = [];
  for (const item of serverItems) {
    if (!nextByVariant.has(item.variantId)) {
      operations.push(
        fetch(`${API}/cart/items/${item.variantId}`, {
          method: 'DELETE',
          headers: { Cookie: cookies },
        }),
      );
    }
  }
  for (const item of items) {
    operations.push(
      fetch(`${API}/cart/items`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Cookie: cookies },
        body: JSON.stringify(item),
      }),
    );
  }
  const results = await Promise.all(operations);
  for (const response of results) {
    if (!response.ok && response.status !== 404) {
      const message = await response.text();
      return { ok: false, status: response.status, message: message || 'Error al sincronizar el carrito' };
    }
  }
  return { ok: true };
}

export async function POST(request: NextRequest) {
  const cookieJar = await cookies();
  const sessionCookie = cookieJar.get(SESSION_COOKIE)?.value;
  if (!sessionCookie) {
    return NextResponse.json(UNAUTHORIZED, { status: 401 });
  }

  const cookieHeader = request.headers.get('cookie') ?? `${SESSION_COOKIE}=${sessionCookie}`;

  let body: RawBody;
  try {
    body = (await request.json()) as RawBody;
  } catch {
    return NextResponse.json(
      { error: { code: 'INVALID_BODY', message: 'Cuerpo JSON inválido.' } },
      { status: 400 },
    );
  }

  const address = body.shippingAddress ?? {};
  const country = isNonEmptyString(address.country) ? address.country : COUNTRY_FALLBACK;
  const postalCode = isNonEmptyString(address.postalCode) ? address.postalCode : null;
  if (!postalCode) {
    return NextResponse.json(
      { error: { code: 'INVALID_ADDRESS', message: 'Falta el código postal.' } },
      { status: 400 },
    );
  }

  let items: { productId: string; variantId: string; quantity: number }[];
  try {
    items = parseItems(body.items);
  } catch (error) {
    return NextResponse.json(
      { error: { code: 'INVALID_CART', message: (error as Error).message } },
      { status: 400 },
    );
  }

  const sync = await syncCart(cookieHeader, items);
  if (!sync.ok) {
    return NextResponse.json(
      { error: { code: 'CART_SYNC_FAILED', message: sync.message } },
      { status: sync.status },
    );
  }

  const idempotencyKey = isNonEmptyString(body.idempotencyKey)
    ? body.idempotencyKey
    : `frontend-${randomUUID()}`;

  let backendRes: Response;
  try {
    backendRes = await fetch(`${API}/checkout`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Cookie: cookieHeader },
      body: JSON.stringify({
        address: { country, postalCode },
        promoCode: body.promoCode ?? null,
        idempotencyKey,
      }),
    });
  } catch (error) {
    return NextResponse.json(
      {
        error: {
          code: 'BACKEND_UNREACHABLE',
          message: `No se pudo conectar con el servidor: ${(error as Error).message}`,
        },
      },
      { status: 502 },
    );
  }

  const text = await backendRes.text();
  let payload: unknown = text;
  try {
    payload = text ? JSON.parse(text) : {};
  } catch {
    // Keep raw text if backend returned non-JSON.
  }

  if (backendRes.status === 401) {
    return NextResponse.json(UNAUTHORIZED, { status: 401 });
  }

  return NextResponse.json(payload, { status: backendRes.status });
}
