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';

// Validation schema for opening a cash register
const openRegisterSchema = z.object({
  siteId: z.string().cuid('Invalid site ID'),
  openingAmount: z.number().nonnegative('Opening amount must be non-negative'),
});

// GET /api/cash-register - Get current open register for site or list all for date
export async function GET(request: NextRequest) {
  try {
    const session = await getServerSession(authOptions);

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

    const { searchParams } = new URL(request.url);
    const siteId = searchParams.get('siteId');
    const date = searchParams.get('date');
    const status = searchParams.get('status'); // 'open', 'closed', or 'all'

    // Build the where clause
    interface RegisterWhereClause {
      site: {
        organizationId: string;
        id?: string;
      };
      closedAt?: null | { not: null } | { gte?: Date; lte?: Date };
      openedAt?: {
        gte?: Date;
        lte?: Date;
      };
    }

    const whereClause: RegisterWhereClause = {
      site: {
        organizationId: session.user.organizationId,
      },
    };

    // Filter by site
    const effectiveSiteId = siteId || session.user.siteId;
    if (effectiveSiteId) {
      // Verify site belongs to user's organization
      const site = await db.site.findFirst({
        where: {
          id: effectiveSiteId,
          organizationId: session.user.organizationId,
        },
      });

      if (!site) {
        return NextResponse.json(
          { error: 'Site not found or does not belong to your organization' },
          { status: 404 }
        );
      }

      whereClause.site.id = effectiveSiteId;
    }

    // Filter by status
    if (status === 'open') {
      whereClause.closedAt = null;
    } else if (status === 'closed') {
      whereClause.closedAt = { not: null };
    }

    // Filter by date
    if (date) {
      const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
      if (dateRegex.test(date)) {
        const startOfDay = new Date(date);
        startOfDay.setHours(0, 0, 0, 0);
        const endOfDay = new Date(date);
        endOfDay.setHours(23, 59, 59, 999);

        whereClause.openedAt = {
          gte: startOfDay,
          lte: endOfDay,
        };
      }
    }

    const registers = await db.cashRegister.findMany({
      where: whereClause,
      include: {
        site: {
          select: {
            id: true,
            name: true,
          },
        },
        user: {
          select: {
            id: true,
            firstName: true,
            lastName: true,
          },
        },
        _count: {
          select: {
            sales: true,
            payments: true,
          },
        },
      },
      orderBy: {
        openedAt: 'desc',
      },
    });

    // If looking for current open register, return just that one
    if (status === 'open' && !date) {
      const openRegister = registers[0] || null;

      if (openRegister) {
        // Get payment breakdown for the open register
        const payments = await db.payment.findMany({
          where: {
            cashRegisterId: openRegister.id,
          },
          select: {
            amount: true,
            paymentType: true,
          },
        });

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

        const totalCashSales = paymentBreakdown['CASH'] || 0;
        const expectedAmount = Number(openRegister.openingAmount) + totalCashSales;

        return NextResponse.json({
          ...openRegister,
          paymentBreakdown,
          totalCashSales,
          expectedAmount,
        });
      }

      return NextResponse.json(null);
    }

    return NextResponse.json(registers);
  } catch (error) {
    console.error('Error fetching cash registers:', error);
    return NextResponse.json(
      { error: 'Failed to fetch cash registers' },
      { status: 500 }
    );
  }
}

// POST /api/cash-register - Open a new cash register
export async function POST(request: NextRequest) {
  try {
    const session = await getServerSession(authOptions);

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

    const body = await request.json();

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

    const { siteId, openingAmount } = validationResult.data;

    // Verify site belongs to user's organization
    const site = await db.site.findFirst({
      where: {
        id: siteId,
        organizationId: session.user.organizationId,
      },
    });

    if (!site) {
      return NextResponse.json(
        { error: 'Site not found or does not belong to your organization' },
        { status: 404 }
      );
    }

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

    // Check if there's already an open register for this site
    const existingOpenRegister = await db.cashRegister.findFirst({
      where: {
        siteId,
        closedAt: null,
      },
      include: {
        user: {
          select: {
            firstName: true,
            lastName: true,
          },
        },
      },
    });

    if (existingOpenRegister) {
      return NextResponse.json(
        {
          error: `There is already an open cash register for this site, opened by ${existingOpenRegister.user.firstName} ${existingOpenRegister.user.lastName}`,
          existingRegisterId: existingOpenRegister.id,
        },
        { status: 409 }
      );
    }

    // Create new cash register
    const cashRegister = await db.cashRegister.create({
      data: {
        siteId,
        userId: session.user.id,
        openingAmount: new Decimal(openingAmount),
      },
      include: {
        site: {
          select: {
            id: true,
            name: true,
          },
        },
        user: {
          select: {
            id: true,
            firstName: true,
            lastName: true,
          },
        },
      },
    });

    return NextResponse.json(cashRegister, { status: 201 });
  } catch (error) {
    console.error('Error opening cash register:', error);
    return NextResponse.json(
      { error: 'Failed to open cash register' },
      { status: 500 }
    );
  }
}
