// app/api/internal/foreign-student/availability/route.js
import pool from '../../../../../lib/db/db';
import { NextRequest, NextResponse } from 'next/server';
import { RowDataPacket } from 'mysql2';
import jwt from 'jsonwebtoken';
import { z } from 'zod';

// Custom boolean preprocessor for handling MySQL booleans (0/1)
const booleanSchema = z.preprocess(
  (val) => {
    if (val === null || val === undefined) return false;
    if (typeof val === 'boolean') return val;
    if (typeof val === 'number') return val === 1;
    if (typeof val === 'string') {
      if (val === '1' || val.toLowerCase() === 'true') return true;
      if (val === '0' || val.toLowerCase() === 'false') return false;
    }
    return Boolean(val);
  },
  z.boolean()
);

// Validation schemas
const timeSlotSchema = z.object({
  start: z.string().regex(/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/, 'Invalid time format'),
  end: z.string().regex(/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/, 'Invalid time format')
}).refine(data => data.start < data.end, {
  message: "End time must be after start time",
  path: ["end"]
});

const dayScheduleSchema = z.object({
  dayId: z.number().min(0).max(6),
  dayName: z.string(),
  isAvailable: booleanSchema,
  timeSlots: z.array(timeSlotSchema)
});

const specialDateSchema = z.object({
  date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Invalid date format'),
  type: z.enum(['available', 'unavailable']),
  reason: z.string().max(255).optional(),
  timeSlots: z.array(timeSlotSchema).default([])
}).refine(data => {
  if (data.type === 'available') {
    return data.timeSlots.length > 0;
  }
  return true;
}, {
  message: "Available dates must have at least one time slot",
  path: ["timeSlots"]
});

const availabilitySchema = z.object({
  weeklySchedule: z.array(dayScheduleSchema),
  specialDates: z.array(specialDateSchema),
  timezone: z.string().default('UTC')
});

// GET - Fetch availability
export async function GET(req: NextRequest) {
  const connection = await pool.getConnection();
  
  try {
    // Get token from cookie
    const token = req.cookies.get('university-token')?.value;
    
    if (!token) {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Authentication required' },
        { status: 401 }
      );
    }

    // Verify token
    let decoded;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET as string);
    } catch (err) {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Invalid or expired token' },
        { status: 401 }
      );
    }

    if (decoded.role !== 'foreign-student') {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Access denied' },
        { status: 403 }
      );
    }

    const studentId = decoded.id;

    // Fetch weekly schedule
    const [weeklyScheduleRows] = await connection.query<RowDataPacket[]>(
      `SELECT 
        id,
        day_of_week, 
        is_available
       FROM foreign_student_weekly_schedule
       WHERE foreign_student_id = ?
       ORDER BY day_of_week`,
      [studentId]
    );

    // Fetch time slots for each schedule
    const processedSchedule = await Promise.all(
      weeklyScheduleRows.map(async (day) => {
        const [timeSlots] = await connection.query<RowDataPacket[]>(
          `SELECT start_time, end_time 
           FROM foreign_student_time_slots 
           WHERE weekly_schedule_id = ?
           ORDER BY start_time`,
          [day.id]
        );

        return {
          day_of_week: day.day_of_week,
          is_available: day.is_available,
          time_slots: timeSlots.map(slot => ({
            start: slot.start_time.substring(0, 5),
            end: slot.end_time.substring(0, 5)
          }))
        };
      })
    );

    // Fetch special dates
    const [specialDatesRows] = await connection.query<RowDataPacket[]>(
      `SELECT 
        id,
        date,
        type,
        reason
       FROM foreign_student_special_dates
       WHERE foreign_student_id = ?
       ORDER BY date DESC
       LIMIT 50`,
      [studentId]
    );

    // Fetch time slots for each special date
    const processedSpecialDates = await Promise.all(
      specialDatesRows.map(async (date) => {
        const [timeSlots] = await connection.query<RowDataPacket[]>(
          `SELECT start_time, end_time 
           FROM foreign_student_special_date_slots 
           WHERE special_date_id = ?
           ORDER BY start_time`,
          [date.id]
        );

        return {
          id: date.id,
          date: date.date,
          type: date.type,
          reason: date.reason,
          time_slots: timeSlots.map(slot => ({
            start: slot.start_time.substring(0, 5),
            end: slot.end_time.substring(0, 5)
          }))
        };
      })
    );

    connection.release();

    return NextResponse.json({
      success: true,
      message: 'Schedule fetched successfully',
      schedule: processedSchedule,
      specialDates: processedSpecialDates
    }, { status: 200 });

  } catch (err: any) {
    if (connection) connection.release();
    console.error('Get availability error:', err);
    return NextResponse.json(
      { success: false, message: 'Failed to fetch schedule' },
      { status: 500 }
    );
  }
}

// POST - Save availability
export async function POST(req: NextRequest) {
  const connection = await pool.getConnection();
  
  try {
    // Get token from cookie
    const token = req.cookies.get('university-token')?.value;
    
    if (!token) {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Authentication required' },
        { status: 401 }
      );
    }

    // Verify token
    let decoded;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET as string);
    } catch (err) {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Invalid or expired token' },
        { status: 401 }
      );
    }

    if (decoded.role !== 'foreign-student') {
      connection.release();
      return NextResponse.json(
        { success: false, message: 'Access denied' },
        { status: 403 }
      );
    }

    const body = await req.json();
    
    // Validate input using the schema with custom boolean preprocessor
    const validatedData = availabilitySchema.parse(body);

    // Start transaction
    await connection.beginTransaction();

    const studentId = decoded.id;

    // Update timezone in foreign_students table
    await connection.query(
      'UPDATE foreign_students SET timezone = ?, updated_at = NOW() WHERE id = ?',
      [validatedData.timezone, studentId]
    );

    // Delete existing weekly schedule and associated time slots
    // First get all schedule IDs to delete time slots
    const [existingSchedules] = await connection.query<RowDataPacket[]>(
      'SELECT id FROM foreign_student_weekly_schedule WHERE foreign_student_id = ?',
      [studentId]
    );

    for (const schedule of existingSchedules) {
      await connection.query(
        'DELETE FROM foreign_student_time_slots WHERE weekly_schedule_id = ?',
        [schedule.id]
      );
    }

    // Delete weekly schedule
    await connection.query(
      'DELETE FROM foreign_student_weekly_schedule WHERE foreign_student_id = ?',
      [studentId]
    );

    // Insert new weekly schedule with time slots
    for (const day of validatedData.weeklySchedule) {
      // Insert the day schedule
      const [scheduleResult] = await connection.query(
        `INSERT INTO foreign_student_weekly_schedule 
         (foreign_student_id, day_of_week, is_available)
         VALUES (?, ?, ?)`,
        [
          studentId,
          day.dayId,
          day.isAvailable ? 1 : 0
        ]
      );

      const scheduleId = (scheduleResult as any).insertId;

      // Insert time slots if day is available and has time slots
      if (day.isAvailable && day.timeSlots.length > 0) {
        for (const timeSlot of day.timeSlots) {
          await connection.query(
            `INSERT INTO foreign_student_time_slots 
             (weekly_schedule_id, start_time, end_time)
             VALUES (?, ?, ?)`,
            [
              scheduleId,
              `${timeSlot.start}:00`,
              `${timeSlot.end}:00`
            ]
          );
        }
      }
    }

    // Delete existing special dates and associated time slots
    // First get all special date IDs to delete time slots
    const [existingSpecialDates] = await connection.query<RowDataPacket[]>(
      'SELECT id FROM foreign_student_special_dates WHERE foreign_student_id = ?',
      [studentId]
    );

    for (const specialDate of existingSpecialDates) {
      await connection.query(
        'DELETE FROM foreign_student_special_date_slots WHERE special_date_id = ?',
        [specialDate.id]
      );
    }

    // Delete special dates
    await connection.query(
      'DELETE FROM foreign_student_special_dates WHERE foreign_student_id = ?',
      [studentId]
    );

    // Insert new special dates with time slots
    for (const specialDate of validatedData.specialDates) {
      // Insert the special date
      const [specialDateResult] = await connection.query(
        `INSERT INTO foreign_student_special_dates 
         (foreign_student_id, date, type, reason)
         VALUES (?, ?, ?, ?)`,
        [
          studentId,
          specialDate.date,
          specialDate.type,
          specialDate.reason || null
        ]
      );

      const specialDateId = (specialDateResult as any).insertId;

      // Insert time slots if date is available and has time slots
      if (specialDate.type === 'available' && specialDate.timeSlots.length > 0) {
        for (const timeSlot of specialDate.timeSlots) {
          await connection.query(
            `INSERT INTO foreign_student_special_date_slots 
             (special_date_id, start_time, end_time)
             VALUES (?, ?, ?)`,
            [
              specialDateId,
              `${timeSlot.start}:00`,
              `${timeSlot.end}:00`
            ]
          );
        }
      }
    }

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

    return NextResponse.json({
      success: true,
      message: 'Schedule updated successfully'
    }, { status: 200 });

  } catch (err: any) {
    // Rollback on any error
    if (connection) {
      await connection.rollback();
      connection.release();
    }
    
    console.log('Save availability 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 }
      );
    }
    
    // Database or other errors
    return NextResponse.json(
      { 
        success: false, 
        message: 'Failed to save schedule',
        error: err
      },
      { status: 500 }
    );
  }
}