import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { db } from '@/lib/db';

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

interface TimeSlot {
  time: string;
  available: boolean;
  price: number;
  bookingId?: string;
}

// Helper function to parse time string (HH:MM) to minutes since midnight
function timeToMinutes(time: string): number {
  const [hours, minutes] = time.split(':').map(Number);
  return hours * 60 + minutes;
}

// Helper function to format minutes to HH:MM
function minutesToTime(minutes: number): string {
  const hours = Math.floor(minutes / 60);
  const mins = minutes % 60;
  return `${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}`;
}

// Helper function to check if a time is premium (after 18:00 or weekend)
function isPremiumTime(date: Date, timeMinutes: number): boolean {
  const dayOfWeek = date.getDay(); // 0 = Sunday, 6 = Saturday
  const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
  const isEveningTime = timeMinutes >= 18 * 60; // After 18:00

  return isWeekend || isEveningTime;
}

// GET /api/courts/[id]/availability - Get availability for a court on a specific date
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: courtId } = await context.params;
    const { searchParams } = new URL(request.url);
    const dateParam = searchParams.get('date');

    // Validate date parameter
    if (!dateParam) {
      return NextResponse.json(
        { error: 'Missing required query parameter: date (YYYY-MM-DD format)' },
        { status: 400 }
      );
    }

    // Parse and validate date format
    const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
    if (!dateRegex.test(dateParam)) {
      return NextResponse.json(
        { error: 'Invalid date format. Use YYYY-MM-DD' },
        { status: 400 }
      );
    }

    const requestedDate = new Date(dateParam);
    if (isNaN(requestedDate.getTime())) {
      return NextResponse.json(
        { error: 'Invalid date value' },
        { status: 400 }
      );
    }

    // Fetch court with site info
    const court = await db.court.findFirst({
      where: {
        id: courtId,
        site: {
          organizationId: session.user.organizationId,
        },
      },
      include: {
        site: {
          select: {
            id: true,
            name: true,
            openTime: true,
            closeTime: true,
            timezone: true,
          },
        },
      },
    });

    if (!court) {
      return NextResponse.json(
        { error: 'Court not found' },
        { status: 404 }
      );
    }

    // Get the start and end of the requested date
    const startOfDay = new Date(dateParam);
    startOfDay.setHours(0, 0, 0, 0);

    const endOfDay = new Date(dateParam);
    endOfDay.setHours(23, 59, 59, 999);

    // Fetch existing bookings for this court on the specified date
    const bookings = await db.booking.findMany({
      where: {
        courtId,
        status: {
          in: ['PENDING', 'CONFIRMED'],
        },
        startTime: {
          gte: startOfDay,
          lte: endOfDay,
        },
      },
      select: {
        id: true,
        startTime: true,
        endTime: true,
      },
      orderBy: {
        startTime: 'asc',
      },
    });

    // Create a map of booked time slots
    const bookedSlots = new Map<string, string>();
    bookings.forEach((booking) => {
      const startHour = booking.startTime.getHours();
      const startMinutes = booking.startTime.getMinutes();
      const timeKey = `${startHour.toString().padStart(2, '0')}:${startMinutes.toString().padStart(2, '0')}`;
      bookedSlots.set(timeKey, booking.id);
    });

    // Generate time slots from open to close (1 hour each)
    const openMinutes = timeToMinutes(court.site.openTime);
    const closeMinutes = timeToMinutes(court.site.closeTime);

    const slots: TimeSlot[] = [];
    const basePrice = Number(court.pricePerHour);
    const premiumMultiplier = 1.25; // 25% premium for evening/weekend

    for (let minutes = openMinutes; minutes < closeMinutes; minutes += 60) {
      const time = minutesToTime(minutes);
      const bookingId = bookedSlots.get(time);
      const isPremium = isPremiumTime(requestedDate, minutes);
      const price = isPremium ? basePrice * premiumMultiplier : basePrice;

      slots.push({
        time,
        available: !bookingId && court.status === 'AVAILABLE' && court.isActive,
        price: Math.round(price * 100) / 100, // Round to 2 decimal places
        ...(bookingId && { bookingId }),
      });
    }

    return NextResponse.json({
      court: {
        id: court.id,
        name: court.name,
        type: court.type,
        status: court.status,
        isActive: court.isActive,
        site: court.site,
      },
      date: dateParam,
      slots,
    });
  } catch (error) {
    console.error('Error fetching court availability:', error);
    return NextResponse.json(
      { error: 'Failed to fetch court availability' },
      { status: 500 }
    );
  }
}
