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 closing a cash register
const closeRegisterSchema = z.object({
  closingAmount: z.number().nonnegative('Closing amount must be non-negative'),
  notes: z.string().max(500).optional(),
});

// GET /api/cash-register/[id] - Get register details with transactions and summary
export async function GET(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const session = await getServerSession(authOptions);

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

    const { id } = await context.params;

    const cashRegister = await db.cashRegister.findFirst({
      where: {
        id,
        site: {
          organizationId: session.user.organizationId,
        },
      },
      include: {
        site: {
          select: {
            id: true,
            name: true,
            address: true,
          },
        },
        user: {
          select: {
            id: true,
            firstName: true,
            lastName: true,
            email: true,
          },
        },
        sales: {
          include: {
            items: {
              include: {
                product: {
                  select: {
                    id: true,
                    name: true,
                  },
                },
              },
            },
            client: {
              select: {
                id: true,
                firstName: true,
                lastName: true,
              },
            },
          },
          orderBy: {
            createdAt: 'desc',
          },
        },
        payments: {
          select: {
            id: true,
            amount: true,
            paymentType: true,
            reference: true,
            notes: true,
            createdAt: true,
            booking: {
              select: {
                id: true,
              },
            },
            sale: {
              select: {
                id: true,
              },
            },
          },
          orderBy: {
            createdAt: 'desc',
          },
        },
      },
    });

    if (!cashRegister) {
      return NextResponse.json(
        { error: 'Cash register not found' },
        { status: 404 }
      );
    }

    // Calculate payment breakdown by method
    const paymentBreakdown = cashRegister.payments.reduce((acc, payment) => {
      const type = payment.paymentType;
      acc[type] = (acc[type] || 0) + Number(payment.amount);
      return acc;
    }, {} as Record<string, number>);

    // Calculate totals
    const totalCashSales = paymentBreakdown['CASH'] || 0;
    const totalCardSales = paymentBreakdown['CARD'] || 0;
    const totalTransferSales = paymentBreakdown['TRANSFER'] || 0;
    const totalMembershipSales = paymentBreakdown['MEMBERSHIP'] || 0;
    const totalFreeSales = paymentBreakdown['FREE'] || 0;

    const totalAllPayments = Object.values(paymentBreakdown).reduce((sum, val) => sum + val, 0);
    const expectedCashAmount = Number(cashRegister.openingAmount) + totalCashSales;

    // Calculate difference if register is closed
    let actualDifference = null;
    if (cashRegister.closedAt && cashRegister.closingAmount !== null) {
      actualDifference = Number(cashRegister.closingAmount) - expectedCashAmount;
    }

    return NextResponse.json({
      ...cashRegister,
      summary: {
        paymentBreakdown,
        totalCashSales,
        totalCardSales,
        totalTransferSales,
        totalMembershipSales,
        totalFreeSales,
        totalAllPayments,
        openingAmount: Number(cashRegister.openingAmount),
        expectedCashAmount,
        closingAmount: cashRegister.closingAmount ? Number(cashRegister.closingAmount) : null,
        difference: actualDifference,
        salesCount: cashRegister.sales.length,
        transactionsCount: cashRegister.payments.length,
      },
    });
  } catch (error) {
    console.error('Error fetching cash register:', error);
    return NextResponse.json(
      { error: 'Failed to fetch cash register' },
      { status: 500 }
    );
  }
}

// PUT /api/cash-register/[id] - Close a cash register
export async function PUT(
  request: NextRequest,
  context: RouteContext
) {
  try {
    const session = await getServerSession(authOptions);

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

    const { id } = await context.params;

    // Fetch the cash register
    const existingRegister = await db.cashRegister.findFirst({
      where: {
        id,
        site: {
          organizationId: session.user.organizationId,
        },
      },
    });

    if (!existingRegister) {
      return NextResponse.json(
        { error: 'Cash register not found' },
        { status: 404 }
      );
    }

    // Check if already closed
    if (existingRegister.closedAt) {
      return NextResponse.json(
        { error: 'Cash register is already closed' },
        { status: 400 }
      );
    }

    // If user is SITE_ADMIN, verify they have access to this site
    if (session.user.role === 'SITE_ADMIN' && session.user.siteId !== existingRegister.siteId) {
      return NextResponse.json(
        { error: 'Forbidden: You do not have access to this cash register' },
        { status: 403 }
      );
    }

    const body = await request.json();

    // Validate input with Zod schema
    const validationResult = closeRegisterSchema.safeParse(body);
    if (!validationResult.success) {
      return NextResponse.json(
        {
          error: 'Invalid close register data',
          details: validationResult.error.flatten().fieldErrors,
        },
        { status: 400 }
      );
    }

    const { closingAmount, notes } = validationResult.data;

    // Calculate expected amount from cash payments
    const cashPayments = await db.payment.aggregate({
      where: {
        cashRegisterId: id,
        paymentType: 'CASH',
      },
      _sum: {
        amount: true,
      },
    });

    const totalCashPayments = cashPayments._sum.amount ? Number(cashPayments._sum.amount) : 0;
    const expectedAmount = Number(existingRegister.openingAmount) + totalCashPayments;
    const difference = closingAmount - expectedAmount;

    // Close the cash register
    const cashRegister = await db.cashRegister.update({
      where: { id },
      data: {
        closedAt: new Date(),
        closingAmount: new Decimal(closingAmount),
        expectedAmount: new Decimal(expectedAmount),
        difference: new Decimal(difference),
        notes: notes || null,
      },
      include: {
        site: {
          select: {
            id: true,
            name: true,
          },
        },
        user: {
          select: {
            id: true,
            firstName: true,
            lastName: true,
          },
        },
      },
    });

    // Get payment breakdown for the response
    const allPayments = await db.payment.findMany({
      where: {
        cashRegisterId: id,
      },
      select: {
        amount: true,
        paymentType: true,
      },
    });

    const paymentBreakdown = allPayments.reduce((acc, payment) => {
      const type = payment.paymentType;
      acc[type] = (acc[type] || 0) + Number(payment.amount);
      return acc;
    }, {} as Record<string, number>);

    return NextResponse.json({
      ...cashRegister,
      summary: {
        paymentBreakdown,
        openingAmount: Number(existingRegister.openingAmount),
        expectedAmount,
        closingAmount,
        difference,
        status: difference === 0 ? 'balanced' : difference > 0 ? 'over' : 'short',
      },
    });
  } catch (error) {
    console.error('Error closing cash register:', error);
    return NextResponse.json(
      { error: 'Failed to close cash register' },
      { status: 500 }
    );
  }
}
