import { NextResponse } from 'next/server';
import { ZodError } from 'zod';
import { Prisma } from '@prisma/client';

// ─── TIPOS ────────────────────────────────────────────────────────────────────

export interface ApiResponse<T = unknown> {
  success: boolean;
  data?: T;
  meta?: {
    total?: number;
    page?: number;
    limit?: number;
  };
  error?: {
    code: string;
    message: string;
    details?: unknown;
  };
}

// ─── RESPUESTAS EXITOSAS ──────────────────────────────────────────────────────

export function ok<T>(data: T, status = 200, meta?: ApiResponse['meta']): NextResponse<ApiResponse<T>> {
  return NextResponse.json({ success: true, data, ...(meta ? { meta } : {}) }, { status });
}

export function created<T>(data: T): NextResponse<ApiResponse<T>> {
  return NextResponse.json({ success: true, data }, { status: 201 });
}

export function noContent(): NextResponse {
  return new NextResponse(null, { status: 204 });
}

// ─── ERRORES ESTÁNDAR ─────────────────────────────────────────────────────────

export function unauthorized(message = 'No autenticado'): NextResponse<ApiResponse> {
  return NextResponse.json(
    { success: false, error: { code: 'UNAUTHORIZED', message } },
    { status: 401 }
  );
}

export function forbidden(message = 'Sin permisos para este recurso'): NextResponse<ApiResponse> {
  return NextResponse.json(
    { success: false, error: { code: 'FORBIDDEN', message } },
    { status: 403 }
  );
}

export function notFound(resource = 'Recurso'): NextResponse<ApiResponse> {
  return NextResponse.json(
    { success: false, error: { code: 'NOT_FOUND', message: `${resource} no encontrado` } },
    { status: 404 }
  );
}

export function badRequest(message: string, details?: unknown): NextResponse<ApiResponse> {
  return NextResponse.json(
    { success: false, error: { code: 'BAD_REQUEST', message, details } },
    { status: 400 }
  );
}

export function conflict(message: string): NextResponse<ApiResponse> {
  return NextResponse.json(
    { success: false, error: { code: 'CONFLICT', message } },
    { status: 409 }
  );
}

export function tooManyRequests(resetAt?: number): NextResponse<ApiResponse> {
  const headers: Record<string, string> = { 'Retry-After': '60' };
  if (resetAt) headers['X-RateLimit-Reset'] = String(Math.ceil(resetAt / 1000));
  return NextResponse.json(
    { success: false, error: { code: 'TOO_MANY_REQUESTS', message: 'Demasiadas solicitudes. Intenta más tarde.' } },
    { status: 429, headers }
  );
}

// ─── MANEJADOR CENTRALIZADO DE ERRORES ───────────────────────────────────────

export function handleApiError(error: unknown): NextResponse<ApiResponse> {
  // Error de validación Zod
  if (error instanceof ZodError) {
    return NextResponse.json(
      {
        success: false,
        error: {
          code: 'VALIDATION_ERROR',
          message: 'Los datos enviados son inválidos',
          details: error.flatten().fieldErrors,
        },
      },
      { status: 422 }
    );
  }

  // Errores conocidos de Prisma
  if (error instanceof Prisma.PrismaClientKnownRequestError) {
    switch (error.code) {
      case 'P2002':
        return conflict('Ya existe un registro con ese identificador único');
      case 'P2025':
        return notFound('El registro');
      case 'P2003':
        return badRequest('Error de integridad referencial: registro relacionado no existe');
      case 'P2014':
        return badRequest('La relación requerida no existe');
      default:
        break;
    }
  }

  // Error de negocio controlado (throw new Error('CODE:mensaje'))
  if (error instanceof Error) {
    const msg = error.message;
    if (msg === 'INVALID_CREDENTIALS') return unauthorized('Credenciales inválidas');
    if (msg === 'EMAIL_INVALID') return badRequest('Correo electrónico inválido');
    if (msg === 'INVALID_REFRESH_TOKEN') return unauthorized('Token de actualización inválido o expirado');
    if (msg === 'USER_INACTIVE') return unauthorized('Usuario inactivo o no encontrado');
    if (msg === 'TABLE_NOT_FOUND') return notFound('Mesa');
    if (msg === 'ORDER_NOT_FOUND') return notFound('Orden');
    if (msg === 'PRODUCT_NOT_FOUND') return notFound('Producto');
    if (msg === 'INVOICE_NOT_FOUND') return notFound('Factura');
    if (msg === 'SHIFT_NOT_OPEN') return badRequest('No hay turno de caja abierto');
    if (msg === 'SHIFT_ALREADY_OPEN') return conflict('Ya hay un turno de caja abierto');
    if (msg.startsWith('INVALID_STATUS')) return badRequest(msg.replace('INVALID_STATUS:', ''));
    if (msg === 'INSUFFICIENT_STOCK') return badRequest('Stock insuficiente para despachar');
    if (msg === 'ONE_OR_MORE_PRODUCTS_UNAVAILABLE')
      return badRequest('Uno o más productos no están disponibles');
    if (msg === 'DISCOUNT_EXCEEDS_SUBTOTAL')
      return badRequest('El descuento no puede ser mayor al subtotal de la orden');
    if (msg === 'INVOICE_HAS_PAYMENTS')
      return badRequest('No se puede anular una factura con pagos registrados; reversa los pagos primero');
    if (msg === 'FORBIDDEN_SHIFT_OWNER')
      return forbidden('Solo el titular del turno o un ADMIN/MANAGER pueden cerrarlo');
    if (msg === 'FORBIDDEN_ORDER_OWNER')
      return forbidden('Solo el mesero que abrió la orden o un ADMIN/MANAGER pueden modificarla');
  }

  // Error interno: registrar pero NO exponer al cliente
  console.error('[API_ERROR]', error);

  return NextResponse.json(
    {
      success: false,
      error: {
        code: 'INTERNAL_SERVER_ERROR',
        message: 'Error interno del servidor. Por favor intente más tarde.',
      },
    },
    { status: 500 }
  );
}
