import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { db } from '@/lib/db';
import { z } from 'zod';
import { Decimal } from '@prisma/client/runtime/library';

interface RouteContext {
  params: Promise<{ id: string }>;
}

// Validation schema for payment
const paymentSchema = z.object({
  paymentType: z.enum(['CASH', 'CARD', 'TRANSFER', 'MEMBERSHIP', 'FREE']),
  amount: z.number().positive('El monto debe ser mayor a 0').optional(),
  reference: z.string().max(100).optional(),
  notes: z.string().max(500).optional(),
  cashRegisterId: z.string().uuid().optional(),
});

// POST /api/bookings/[id]/pay - Mark booking as paid
export async function POST(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const session = await getServerSession(authOptions);

    if (!session?.user) {
      return NextResponse.json(
        { error: 'No autorizado' },
        { status: 401 }
      );
    }

    const { id } = await context.params;

    // Verify booking exists and belongs to user's organization
    const existingBooking = await db.booking.findFirst({
      where: {
        id,
        site: {
          organizationId: session.user.organizationId,
        },
      },
      include: {
        client: true,
        payments: true,
      },
    });

    if (!existingBooking) {
      return NextResponse.json(
        { error: 'Reserva no encontrada' },
        { status: 404 }
      );
    }

    // If user is SITE_ADMIN, verify they have access to this site
    if (session.user.role === 'SITE_ADMIN' && session.user.siteId !== existingBooking.siteId) {
      return NextResponse.json(
        { error: 'No tiene permiso para procesar pagos en esta reserva' },
        { status: 403 }
      );
    }

    // Check if booking is already cancelled
    if (existingBooking.status === 'CANCELLED') {
      return NextResponse.json(
        { error: 'No se puede procesar el pago de una reserva cancelada' },
        { status: 400 }
      );
    }

    // Check if booking is already fully paid
    const totalPaid = existingBooking.payments.reduce(
      (sum, p) => sum + Number(p.amount),
      0
    );
    const totalPrice = Number(existingBooking.totalPrice);

    if (totalPaid >= totalPrice) {
      return NextResponse.json(
        { error: 'La reserva ya está completamente pagada' },
        { status: 400 }
      );
    }

    const body = await request.json();

    // Validate input
    const validationResult = paymentSchema.safeParse(body);
    if (!validationResult.success) {
      return NextResponse.json(
        {
          error: 'Datos de pago inválidos',
          details: validationResult.error.flatten().fieldErrors,
        },
        { status: 400 }
      );
    }

    const { paymentType, amount, reference, notes, cashRegisterId } = validationResult.data;

    // Calculate payment amount
    const remainingAmount = totalPrice - totalPaid;
    const paymentAmount = amount !== undefined ? Math.min(amount, remainingAmount) : remainingAmount;

    if (paymentAmount <= 0) {
      return NextResponse.json(
        { error: 'El monto del pago debe ser mayor a 0' },
        { status: 400 }
      );
    }

    // If cash register is provided, verify it exists and is open
    if (cashRegisterId) {
      const cashRegister = await db.cashRegister.findFirst({
        where: {
          id: cashRegisterId,
          siteId: existingBooking.siteId,
          closedAt: null, // Only open registers
        },
      });

      if (!cashRegister) {
        return NextResponse.json(
          { error: 'Caja registradora no encontrada o no está abierta' },
          { status: 400 }
        );
      }
    }

    // Use transaction for atomicity
    const result = await db.$transaction(async (tx) => {
      // Create payment record
      const payment = await tx.payment.create({
        data: {
          bookingId: id,
          clientId: existingBooking.clientId,
          amount: new Decimal(paymentAmount),
          paymentType,
          reference: reference || null,
          notes: notes || null,
          cashRegisterId: cashRegisterId || null,
        },
      });

      // Calculate new total paid
      const newTotalPaid = totalPaid + paymentAmount;
      const isFullyPaid = newTotalPaid >= totalPrice;

      // Update booking
      const updatedBooking = await tx.booking.update({
        where: { id },
        data: {
          paidAmount: new Decimal(newTotalPaid),
          paymentType,
          // Set status to CONFIRMED if fully paid and was pending
          ...(isFullyPaid && existingBooking.status === 'PENDING' && {
            status: 'CONFIRMED',
          }),
        },
        include: {
          court: {
            select: {
              id: true,
              name: true,
              type: true,
              pricePerHour: true,
            },
          },
          client: {
            select: {
              id: true,
              firstName: true,
              lastName: true,
              email: true,
              phone: true,
            },
          },
          site: {
            select: {
              id: true,
              name: true,
              timezone: true,
            },
          },
          payments: {
            select: {
              id: true,
              amount: true,
              paymentType: true,
              reference: true,
              notes: true,
              createdAt: true,
            },
            orderBy: {
              createdAt: 'desc',
            },
          },
        },
      });

      return {
        booking: updatedBooking,
        payment,
        isFullyPaid,
      };
    });

    return NextResponse.json({
      message: result.isFullyPaid
        ? 'Pago completado. La reserva ha sido confirmada.'
        : 'Pago parcial registrado exitosamente.',
      booking: result.booking,
      payment: result.payment,
      remainingAmount: Math.max(0, totalPrice - (totalPaid + paymentAmount)),
    });
  } catch (error) {
    console.error('Error processing payment:', error);
    return NextResponse.json(
      { error: 'Error al procesar el pago' },
      { status: 500 }
    );
  }
}
