// app/api/appapis/book-appointment/route.js
import { NextRequest, NextResponse } from 'next/server';
import pool from '../../../../lib/db/db';
import { ResultSetHeader, RowDataPacket } from 'mysql2';
import { verifyAuthentication } from '../../../utils/verifyAuthentication';
import { z } from 'zod';

// Validation schema
const bookingSchema = z.object({
  foreignStudentId: z.number().min(1, 'Foreign student ID is required'),
  sessionDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Invalid date format'),
  startTime: z.string().regex(/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/, 'Invalid time format'),
  endTime: z.string().regex(/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/, 'Invalid time format'),
  amount: z.number().min(0).optional()
}).refine(data => data.startTime < data.endTime, {
  message: "End time must be after start time",
  path: ["endTime"]
});

// CORS headers
const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization, x-api-key',
  'Access-Control-Allow-Credentials': 'true',
};

export async function OPTIONS() {
  return new NextResponse(null, {
    status: 204,
    headers: corsHeaders,
  });
}

// Helper function to calculate duration in hours
const calculateDurationHours = (startTime: string, endTime: string): number => {
  const [startHour, startMinute] = startTime.split(':').map(Number);
  const [endHour, endMinute] = endTime.split(':').map(Number);
  
  const startTotal = startHour * 60 + startMinute;
  const endTotal = endHour * 60 + endMinute;
  
  return (endTotal - startTotal) / 60;
};

// Helper function to calculate amount
const calculateAmount = (hourRate: number, startTime: string, endTime: string): number => {
  const durationHours = calculateDurationHours(startTime, endTime);
  return (hourRate || 0) * durationHours;
};

export async function POST(request: NextRequest) {
  const connection = await pool.getConnection();
  
  try {
    // Get token from Authorization header for mobile app
    const authHeader = request.headers.get('authorization');
    
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'No valid authorization header found' },
        { status: 401, headers: corsHeaders }
      );
    }

    const token = authHeader.substring(7);
    
    // Verify token
    const authResult = await verifyAuthentication(token);
    
    if (authResult instanceof NextResponse) {
      connection.release();
      return authResult;
    }
    
    const decoded = authResult as { id: number; role: string };
    
    if (!decoded || !decoded.id) {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Invalid token - no user ID found' },
        { status: 401, headers: corsHeaders }
      );
    }

    // Check if user is a student
    if (decoded.role !== 'student') {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Access denied. Only students can book appointments.' },
        { status: 403, headers: corsHeaders }
      );
    }

    const body = await request.json();
    
    // Validate input
    const validatedData = bookingSchema.parse(body);

    const studentId = decoded.id;
    const { foreignStudentId, sessionDate, startTime, endTime } = validatedData;

    // Check if student exists and is active
    const [studentExists] = await connection.query<RowDataPacket[]>(
      'SELECT id, first_name, email FROM users WHERE id = ? AND is_active = 1 AND user_type = "student"',
      [studentId]
    );

    if (studentExists.length === 0) {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Student not found or account inactive' },
        { status: 404, headers: corsHeaders }
      );
    }

    // Start transaction
    await connection.beginTransaction();

    // 1. Check if foreign student exists and is active
    const [foreignStudent] = await connection.query<RowDataPacket[]>(
      'SELECT id, name, hour_rate, is_active, is_verified FROM foreign_students WHERE id = ? AND is_active = 1',
      [foreignStudentId]
    );

    if (foreignStudent.length === 0) {
      await connection.rollback();
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Tutor not found or not available' },
        { status: 404, headers: corsHeaders }
      );
    }

    const tutor = foreignStudent[0];
    
    if (!tutor.is_active) {
      await connection.rollback();
      connection.release();
      return NextResponse.json(
        { success: false, message: 'This tutor is not currently available for bookings' },
        { status: 400, headers: corsHeaders }
      );
    }

    // 2. Check if time slot is available
    const sessionDay = new Date(sessionDate).getDay();
    
    // Check weekly availability
    const [weeklySchedule] = await connection.query<RowDataPacket[]>(
      `SELECT ws.id, ws.is_available, ts.start_time, ts.end_time
       FROM foreign_student_weekly_schedule ws
       INNER JOIN foreign_student_time_slots ts ON ws.id = ts.weekly_schedule_id
       WHERE ws.foreign_student_id = ?
       AND ws.day_of_week = ?
       AND ws.is_available = 1
       AND ts.start_time <= ?
       AND ts.end_time >= ?`,
      [foreignStudentId, sessionDay, `${endTime}:00`, `${startTime}:00`]
    );

    // Check special dates
    const [specialDate] = await connection.query<RowDataPacket[]>(
      `SELECT sd.id, sds.start_time, sds.end_time
       FROM foreign_student_special_dates sd
       INNER JOIN foreign_student_special_date_slots sds ON sd.id = sds.special_date_id
       WHERE sd.foreign_student_id = ?
       AND sd.date = ?
       AND sd.type = 'available'
       AND sds.start_time <= ?
       AND sds.end_time >= ?`,
      [foreignStudentId, sessionDate, `${endTime}:00`, `${startTime}:00`]
    );

    if (weeklySchedule.length === 0 && specialDate.length === 0) {
      await connection.rollback();
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Selected time slot is not available' },
        { status: 400, headers: corsHeaders }
      );
    }

    // 3. Check for existing bookings at same time
    const [existingBooking] = await connection.query<RowDataPacket[]>(
      `SELECT id, status FROM foreign_student_booked_sessions 
       WHERE foreign_student_id = ?
       AND session_date = ?
       AND (
         (start_time < ? AND end_time > ?) OR
         (start_time >= ? AND start_time < ?)
       )
       AND status IN ('pending', 'confirmed', 'completed')`,
      [
        foreignStudentId,
        sessionDate,
        `${endTime}:00`,
        `${startTime}:00`,
        `${startTime}:00`,
        `${endTime}:00`
      ]
    );

    if (existingBooking.length > 0) {
      await connection.rollback();
      connection.release();
      return NextResponse.json(
        { success: false, message: `Time slot is already booked (Status: ${existingBooking[0].status})` },
        { status: 400, headers: corsHeaders }
      );
    }

    // 4. Calculate amount based on current hour_rate
    const durationHours = calculateDurationHours(startTime, endTime);
    const amount = (tutor.hour_rate || 0) * durationHours;

    // 5. Create booking with amount
    const [insertNewAppointment] = await connection.query<ResultSetHeader>(
      `INSERT INTO foreign_student_booked_sessions 
       (foreign_student_id, student_id, session_date, start_time, end_time, amount, status, created_at, updated_at)
       VALUES (?, ?, ?, ?, ?, ?, 'pending', NOW(), NOW())`,
      [
        foreignStudentId,
        studentId,
        sessionDate,
        `${startTime}:00`,
        `${endTime}:00`,
        amount
      ]
    );

    if (insertNewAppointment.affectedRows === 0) {
      await connection.rollback();
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Failed to book appointment' },
        { status: 500, headers: corsHeaders }
      );
    }

    const appointmentId = insertNewAppointment.insertId;

    // 6. Prepare payload for CRM
    const crmPayload = {
      appointment_id: appointmentId,
      foreign_student_id: foreignStudentId,
      foreign_student_name: tutor.name,
      student_id: studentId,
      student_name: `${studentExists[0].first_name}`,
      student_email: studentExists[0].email,
      session_date: sessionDate,
      start_time: `${startTime}:00`,
      end_time: `${endTime}:00`,
      amount: amount,
      duration_hours: durationHours,
      rate_per_hour: tutor.hour_rate,
      status: "pending",
      booking_source: "mobile_app",
      created_at: new Date().toISOString()
    };

    // 7. Send to CRM API (async - don't wait for response to avoid blocking)
    fetch("https://crm-universitiespage.com/reactapis/api/website_foreign_student_session/store", {
      method: "POST",
      body: JSON.stringify(crmPayload),
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `${process.env.CRM_API_KEY}`,
      },
    }).catch(crmError => {
      console.error('CRM API Error (non-blocking):', crmError);
    });

    // Commit transaction
    await connection.commit();
    connection.release();

    // Format response
    const formatTime = (time: string) => {
      const [hours, minutes] = time.split(':');
      const hour = parseInt(hours);
      const ampm = hour >= 12 ? 'PM' : 'AM';
      const formattedHour = hour % 12 || 12;
      return `${formattedHour}:${minutes} ${ampm}`;
    };

    const formatDate = (dateString: string) => {
      const date = new Date(dateString);
      return date.toLocaleDateString('en-US', {
        weekday: 'long',
        year: 'numeric',
        month: 'long',
        day: 'numeric'
      });
    };

    return NextResponse.json({
      success: true,
      message: 'Appointment booked successfully',
      data: {
        appointmentId: appointmentId,
        tutor: {
          id: tutor.id,
          name: tutor.name,
          rate: tutor.hour_rate
        },
        session: {
          date: sessionDate,
          formattedDate: formatDate(sessionDate),
          startTime: startTime,
          endTime: endTime,
          formattedStartTime: formatTime(startTime),
          formattedEndTime: formatTime(endTime),
          durationHours: durationHours,
          formattedDuration: durationHours === 1 ? '1 hour' : `${durationHours} hours`
        },
        amount: amount,
        formattedAmount: `$${amount.toFixed(2)}`,
        status: 'pending',
        bookingReference: `BOOK-${appointmentId}-${Date.now()}`
      }
    }, { status: 200, headers: corsHeaders });

  } catch (err: any) {
    // Rollback on any error
    if (connection) {
      await connection.rollback();
      connection.release();
    }
    
    console.error('Booking error:', err);
    
    // Zod validation errors
    if (err instanceof z.ZodError) {
      const errors = {};
      err.errors.forEach(error => {
        const path = error.path.join('.');
        errors[path] = error.message;
      });
      
      return NextResponse.json(
        { 
          success: false, 
          message: 'Validation failed', 
          errors 
        },
        { status: 400, headers: corsHeaders }
      );
    }
    
    // Database or other errors
    return NextResponse.json(
      { 
        success: false, 
        message: err.message || 'Failed to book appointment. Please try again.' 
      },
      { status: 500, headers: corsHeaders }
    );
  }
}