const BookingSubmission = require('../models/bookingSubmission');
const Activity = require('../models/activity');

// API endpoint để tạo booking submission mới
exports.submitBooking = async (req, res) => {
  try {
    const {
      activityId,
      sessionId,
      parentFirstName,
      parentLastName,
      email,
      phone,
      address,
      city,
      country,
      postalCode,
      participantFirstName,
      participantLastName,
      participantBirthDate,
      participantGender,
      numberOfParticipants,
      medicalConditions,
      dietaryRestrictions,
      specialRequests,
      emergencyContact,
      emergencyPhone,
      agreeTerms,
      agreeNewsletter
    } = req.body;

    // Validate required fields
    if (!activityId || !sessionId || !parentFirstName || !parentLastName || 
        !email || !phone || !address || !city || !country || !postalCode ||
        !participantFirstName || !participantLastName || !participantBirthDate ||
        !participantGender || !emergencyContact || !emergencyPhone || !agreeTerms) {
      return res.status(400).json({
        error: 'Missing required fields',
        message: 'Please fill in all required fields'
      });
    }

    // Verify activity exists
    const activity = await Activity.findById(activityId);
    if (!activity) {
      return res.status(404).json({
        error: 'Activity not found',
        message: 'The selected activity does not exist'
      });
    }

    // Verify session exists and is active
    const session = activity.bookingSessions?.find(s => s.sessionId === sessionId);
    if (!session) {
      return res.status(404).json({
        error: 'Session not found',
        message: 'The selected session does not exist'
      });
    }

    if (!session.isActive) {
      return res.status(400).json({
        error: 'Session not available',
        message: 'The selected session is no longer available for booking'
      });
    }

    // Check availability based on participant gender
    const currentBookings = await BookingSubmission.countDocuments({
      activityId,
      sessionId,
      participantGender,
      status: { $in: ['pending', 'confirmed'] }
    });

    const availableSpots = participantGender === 'male' 
      ? session.totalMaleSpots - session.bookedMaleSpots
      : session.totalFemaleSpots - session.bookedFemaleSpots;

    if (currentBookings >= availableSpots) {
      return res.status(400).json({
        error: 'Session full',
        message: `No more spots available for ${participantGender} participants in this session`
      });
    }

    // Calculate total amount based on activity price and number of participants
    const totalAmount = (activity.price || 0) * (parseInt(numberOfParticipants) || 1);

    // Create booking submission
    const bookingSubmission = new BookingSubmission({
      activityId,
      sessionId,
      parentFirstName: parentFirstName.trim(),
      parentLastName: parentLastName.trim(),
      email: email.toLowerCase().trim(),
      phone: phone.trim(),
      address: address.trim(),
      city: city.trim(),
      country: country.trim(),
      postalCode: postalCode.trim(),
      participantFirstName: participantFirstName.trim(),
      participantLastName: participantLastName.trim(),
      participantBirthDate: new Date(participantBirthDate),
      participantGender,
      numberOfParticipants: parseInt(numberOfParticipants) || 1,
      medicalConditions: (medicalConditions || '').trim(),
      dietaryRestrictions: dietaryRestrictions || 'none',
      specialRequests: (specialRequests || '').trim(),
      emergencyContact: emergencyContact.trim(),
      emergencyPhone: emergencyPhone.trim(),
      agreeTerms: Boolean(agreeTerms),
      agreeNewsletter: Boolean(agreeNewsletter),
      totalAmount,
      status: 'pending',
      paymentStatus: 'pending'
    });

    await bookingSubmission.save();

    // Update session booked spots
    const updateField = participantGender === 'male' ? 'bookingSessions.$.bookedMaleSpots' : 'bookingSessions.$.bookedFemaleSpots';
    await Activity.updateOne(
      { _id: activityId, 'bookingSessions.sessionId': sessionId },
      { $inc: { [updateField]: 1 } }
    );

    // Populate activity info for response
    await bookingSubmission.populate('activityId', 'name price');

    return res.status(201).json({
      success: true,
      message: 'Booking submitted successfully',
      booking: {
        id: bookingSubmission._id,
        activityName: bookingSubmission.activityId.name,
        sessionId: bookingSubmission.sessionId,
        participantName: `${bookingSubmission.participantFirstName} ${bookingSubmission.participantLastName}`,
        totalAmount: bookingSubmission.totalAmount,
        status: bookingSubmission.status
      }
    });

  } catch (error) {
    console.error('submitBooking error:', error);
    
    // Handle validation errors
    if (error.name === 'ValidationError') {
      const validationErrors = Object.values(error.errors).map(err => err.message);
      return res.status(400).json({
        error: 'Validation failed',
        message: validationErrors.join(', ')
      });
    }

    return res.status(500).json({
      error: 'Server error',
      message: 'An error occurred while processing your booking. Please try again.'
    });
  }
};

// API endpoint để lấy thông tin session availability
exports.getSessionAvailability = async (req, res) => {
  try {
    const { activityId, sessionId } = req.params;

    const activity = await Activity.findById(activityId);
    if (!activity) {
      return res.status(404).json({ error: 'Activity not found' });
    }

    const session = activity.bookingSessions?.find(s => s.sessionId === sessionId);
    if (!session) {
      return res.status(404).json({ error: 'Session not found' });
    }

    // Get current booking counts
    const maleBookings = await BookingSubmission.countDocuments({
      activityId,
      sessionId,
      participantGender: 'male',
      status: { $in: ['pending', 'confirmed'] }
    });

    const femaleBookings = await BookingSubmission.countDocuments({
      activityId,
      sessionId,
      participantGender: 'female',
      status: { $in: ['pending', 'confirmed'] }
    });

    return res.json({
      sessionId,
      isActive: session.isActive,
      startDate: session.startDate,
      endDate: session.endDate,
      overnightStays: session.overnightStays,
      price: session.price || activity.price,
      availability: {
        male: {
          total: session.totalMaleSpots,
          booked: maleBookings,
          available: Math.max(0, session.totalMaleSpots - maleBookings)
        },
        female: {
          total: session.totalFemaleSpots,
          booked: femaleBookings,
          available: Math.max(0, session.totalFemaleSpots - femaleBookings)
        }
      }
    });

  } catch (error) {
    console.error('getSessionAvailability error:', error);
    return res.status(500).json({ error: 'Error loading session availability' });
  }
};

// API endpoint để lấy tất cả sessions có sẵn cho một activity
exports.getAvailableSessions = async (req, res) => {
  try {
    const { activityId } = req.params;

    const activity = await Activity.findById(activityId);
    if (!activity) {
      return res.status(404).json({ error: 'Activity not found' });
    }

    const sessions = activity.bookingSessions || [];
    const availableSessions = [];

    for (const session of sessions) {
      if (!session.isActive) continue;

      // Get current booking counts
      const maleBookings = await BookingSubmission.countDocuments({
        activityId,
        sessionId: session.sessionId,
        participantGender: 'male',
        status: { $in: ['pending', 'confirmed'] }
      });

      const femaleBookings = await BookingSubmission.countDocuments({
        activityId,
        sessionId: session.sessionId,
        participantGender: 'female',
        status: { $in: ['pending', 'confirmed'] }
      });

      const maleAvailable = Math.max(0, session.totalMaleSpots - maleBookings);
      const femaleAvailable = Math.max(0, session.totalFemaleSpots - femaleBookings);

      // Only include sessions that have available spots
      if (maleAvailable > 0 || femaleAvailable > 0) {
        availableSessions.push({
          sessionId: session.sessionId,
          startDate: session.startDate,
          endDate: session.endDate,
          overnightStays: session.overnightStays,
          price: session.price || activity.price,
          availability: {
            male: {
              total: session.totalMaleSpots,
              booked: maleBookings,
              available: maleAvailable
            },
            female: {
              total: session.totalFemaleSpots,
              booked: femaleBookings,
              available: femaleAvailable
            }
          }
        });
      }
    }

    return res.json({
      activityId,
      activityName: activity.name,
      sessions: availableSessions
    });

  } catch (error) {
    console.error('getAvailableSessions error:', error);
    return res.status(500).json({ error: 'Error loading available sessions' });
  }
};

// API endpoint để cập nhật booking submission
exports.updateBookingSubmission = async (req, res) => {
  try {
    const { bookingId } = req.params;
    const updateData = req.body;

    // Find the booking
    let booking = await BookingSubmission.findById(bookingId);

    // If not found as a separate document, try to find it as an embedded booking in Activity.bookingSessions
    let activityContaining = null;
    let sessionIndex = -1;
    let bookingIndex = -1;
    if (!booking) {
      activityContaining = await Activity.findOne({ 'bookingSessions.bookingList._id': bookingId });
      if (!activityContaining) {
        return res.status(404).json({ 
          error: 'Booking not found',
          message: 'The booking submission does not exist'
        });
      }

      // locate the exact session and booking positions
      for (let si = 0; si < activityContaining.bookingSessions.length; si++) {
        const bl = activityContaining.bookingSessions[si].bookingList || [];
        const bi = bl.findIndex(b => b._id && b._id.toString() === bookingId.toString());
        if (bi !== -1) {
          sessionIndex = si;
          bookingIndex = bi;
          break;
        }
      }

      if (sessionIndex === -1 || bookingIndex === -1) {
        return res.status(404).json({ error: 'Booking not found', message: 'The booking submission does not exist' });
      }

      booking = activityContaining.bookingSessions[sessionIndex].bookingList[bookingIndex];
    }

    // Define allowed fields to update
    const allowedUpdates = [
      'status',
      'paymentStatus', 
      'paidAmount',
      'totalAmount',
      'adminNotes',
      'emergencyContact',
      'emergencyPhone',
      'medicalConditions',
      'dietaryRestrictions',
      'specialRequests'
    ];

    // Build update object with only allowed fields
    const updateFields = {};
    for (const field of allowedUpdates) {
      if (updateData[field] !== undefined) {
        updateFields[field] = updateData[field];
      }
    }

    if (Object.keys(updateFields).length === 0) {
      return res.status(400).json({
        error: 'No valid fields to update',
        message: 'Please provide at least one valid field to update'
      });
    }

    // If booking is a separate document, update the BookingSubmission collection
    if (activityContaining === null) {
      const updatedBooking = await BookingSubmission.findByIdAndUpdate(
        bookingId,
        updateFields,
        { new: true, runValidators: true }
      ).populate('activityId', 'name price');

      return res.json({
        success: true,
        message: 'Booking updated successfully',
        booking: updatedBooking
      });
    }

    // Otherwise update the embedded booking in the Activity document
    const currentBooking = activityContaining.bookingSessions[sessionIndex].bookingList[bookingIndex];

    // Handle status updates and spot adjustments
    const newStatus = updateData.status || updateData.bookingStatus;
    const currentStatus = currentBooking.status || currentBooking.bookingStatus;

    // Apply allowed updates to the embedded booking
    const allowedEmbeddedUpdates = [
      'status', 'bookingStatus', 'paymentStatus', 'paidAmount', 'totalAmount', 'adminNotes',
      'emergencyContact', 'emergencyPhone', 'medicalConditions', 'dietaryRestrictions', 'specialRequests'
    ];

    for (const field of allowedEmbeddedUpdates) {
      if (updateData[field] !== undefined) {
        if (field === 'status') {
          activityContaining.bookingSessions[sessionIndex].bookingList[bookingIndex].status = updateData.status;
          activityContaining.bookingSessions[sessionIndex].bookingList[bookingIndex].bookingStatus = updateData.status;
        } else {
          activityContaining.bookingSessions[sessionIndex].bookingList[bookingIndex][field] = updateData[field];
        }
      }
    }

    // If status change affects spots, adjust counts
    if (newStatus && newStatus !== currentStatus) {
      const numberOfParticipants = currentBooking.numberOfParticipants || 1;
      const participantGender = currentBooking.participantGender;

      // If booking is being cancelled, free up spots
      if (newStatus === 'cancelled' && currentStatus !== 'cancelled') {
        if (participantGender === 'male') {
          activityContaining.bookingSessions[sessionIndex].bookedMaleSpots = Math.max(0, activityContaining.bookingSessions[sessionIndex].bookedMaleSpots - numberOfParticipants);
        } else if (participantGender === 'female') {
          activityContaining.bookingSessions[sessionIndex].bookedFemaleSpots = Math.max(0, activityContaining.bookingSessions[sessionIndex].bookedFemaleSpots - numberOfParticipants);
        }
      }

      // If restoring from cancelled, ensure capacity then book spots
      if (currentStatus === 'cancelled' && newStatus !== 'cancelled') {
        if (participantGender === 'male') {
          const totalMale = activityContaining.bookingSessions[sessionIndex].totalMaleSpots;
          const currentMale = activityContaining.bookingSessions[sessionIndex].bookedMaleSpots;
          if (currentMale + numberOfParticipants > totalMale) {
            return res.status(400).json({ error: "Not enough male spots available to restore this booking" });
          }
          activityContaining.bookingSessions[sessionIndex].bookedMaleSpots += numberOfParticipants;
        } else if (participantGender === 'female') {
          const totalFemale = activityContaining.bookingSessions[sessionIndex].totalFemaleSpots;
          const currentFemale = activityContaining.bookingSessions[sessionIndex].bookedFemaleSpots;
          if (currentFemale + numberOfParticipants > totalFemale) {
            return res.status(400).json({ error: "Not enough female spots available to restore this booking" });
          }
          activityContaining.bookingSessions[sessionIndex].bookedFemaleSpots += numberOfParticipants;
        }
      }
    }

    await activityContaining.save();

    return res.json({
      success: true,
      message: 'Embedded booking updated successfully',
      booking: activityContaining.bookingSessions[sessionIndex].bookingList[bookingIndex]
    });

  } catch (error) {
    console.error('updateBookingSubmission error:', error);
    
    // Handle validation errors
    if (error.name === 'ValidationError') {
      const validationErrors = Object.values(error.errors).map(err => err.message);
      return res.status(400).json({
        error: 'Validation failed',
        message: validationErrors.join(', ')
      });
    }

    return res.status(500).json({
      error: 'Server error', 
      message: 'An error occurred while updating the booking'
    });
  }
};

// API endpoint để xóa booking submission
exports.deleteBookingSubmission = async (req, res) => {
  try {
    const { bookingId } = req.params;

    // Find and delete the booking
      let booking = await BookingSubmission.findById(bookingId);

      // If not found in separate collection, try to delete embedded booking in Activity
      if (!booking) {
        const activityContaining = await Activity.findOne({ 'bookingSessions.bookingList._id': bookingId });
        if (!activityContaining) {
          return res.status(404).json({ 
            error: 'Booking not found',
            message: 'The booking submission does not exist'
          });
        }

        // locate session and booking
        let sessionIndex = -1;
        let bookingIndex = -1;
        for (let si = 0; si < activityContaining.bookingSessions.length; si++) {
          const bl = activityContaining.bookingSessions[si].bookingList || [];
          const bi = bl.findIndex(b => b._id && b._id.toString() === bookingId.toString());
          if (bi !== -1) {
            sessionIndex = si;
            bookingIndex = bi;
            break;
          }
        }

        if (sessionIndex === -1 || bookingIndex === -1) {
          return res.status(404).json({ error: 'Booking not found', message: 'The booking submission does not exist' });
        }

        const bookingToDelete = activityContaining.bookingSessions[sessionIndex].bookingList[bookingIndex];

        // Free up spots if booking is not cancelled
        if ((bookingToDelete.bookingStatus || bookingToDelete.status) !== 'cancelled') {
          const numberOfParticipants = bookingToDelete.numberOfParticipants || 1;
          const participantGender = bookingToDelete.participantGender;

          if (participantGender === 'male') {
            activityContaining.bookingSessions[sessionIndex].bookedMaleSpots = Math.max(0, activityContaining.bookingSessions[sessionIndex].bookedMaleSpots - numberOfParticipants);
          } else if (participantGender === 'female') {
            activityContaining.bookingSessions[sessionIndex].bookedFemaleSpots = Math.max(0, activityContaining.bookingSessions[sessionIndex].bookedFemaleSpots - numberOfParticipants);
          }
        }

        // Remove booking and save
        activityContaining.bookingSessions[sessionIndex].bookingList.splice(bookingIndex, 1);
        await activityContaining.save();

        return res.json({
          success: true,
          message: 'Embedded booking deleted successfully',
          booking: {
            id: bookingId,
            participantName: `${bookingToDelete.participantFirstName} ${bookingToDelete.participantLastName}`,
            email: bookingToDelete.email
          }
        });
      }

    // Store info for session spot adjustment
    const { activityId, sessionId, participantGender, numberOfParticipants } = booking;

    // Delete the booking
    await BookingSubmission.findByIdAndDelete(bookingId);

    // Update session booked spots (decrease the count)
    if (booking.status !== 'cancelled') {
      const updateField = participantGender === 'male' 
        ? 'bookingSessions.$.bookedMaleSpots' 
        : 'bookingSessions.$.bookedFemaleSpots';
        
      await Activity.updateOne(
        { _id: activityId, 'bookingSessions.sessionId': sessionId },
        { $inc: { [updateField]: -numberOfParticipants } }
      );
    }

    return res.json({
      success: true,
      message: 'Booking deleted successfully',
      booking: {
        id: bookingId,
        participantName: `${booking.participantFirstName} ${booking.participantLastName}`,
        email: booking.email
      }
    });

  } catch (error) {
    console.error('deleteBookingSubmission error:', error);
    return res.status(500).json({
      error: 'Server error',
      message: 'An error occurred while deleting the booking'
    });
  }
};