<?php

namespace RadiusTheme\RadiusBooking\Repositories;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

use RadiusTheme\RadiusBooking\Abstracts\BaseRepository;
use RadiusTheme\RadiusBooking\Core\Container\Container;
use RadiusTheme\RadiusBooking\Models\Appointment;
use RadiusTheme\RadiusBooking\Models\CustomerBooking;
use RadiusTheme\RadiusBooking\Models\Payment;
use RadiusTheme\RadiusBooking\Models\User;

/**
 * Class BookingRepository
 *
 * Handles data operations for the Booking model.
 */
class BookingRepository extends BaseRepository {

	/**
	 * The model class managed by this repository.
	 *
	 * @var string
	 */
	protected string $model = CustomerBooking::class;


	/**
	 * Calculates the booking price for an appointment based on the provided appointment data.
	 *
	 * @param array $appointmentData An associative array containing the appointment details.
	 *                               Expected keys include 'employee_id' and 'service_id'.
	 *
	 * @return float The calculated booking price. Returns 0.0 if the required data is not provided or no price is determined.
	 */
	public function calculateBookingPriceForAppointment( array $appointmentData ): float {
		$employee_id = $appointmentData['employee_id'] ?? null;
		$service_id  = $appointmentData['service_id'] ?? null;

		if ( ! $employee_id || ! $service_id ) {
			return 0.0;
		}

		$empRepo        = Container::resolve( EmployeeRepository::class );
		$employee_price = $empRepo->getEmployeePrice( $employee_id, $service_id );

		return (float) ( $employee_price ?? 0 );
	}

	/**
	 *
	 * Calculates the total booking price for a given customer.
	 *
	 * @param int $customerId The ID of the customer whose bookings' total price is to be calculated.
	 *
	 * @return float The total price of all bookings for the specified customer.
	 */
	public function getCustomerTotalBookingPrice( $customerId ) {
		$bookings = $this->model::where( 'customer_id', $customerId )->get();
		$total    = 0.0;

		foreach ( $bookings as $booking ) {
			$total += $booking->price;
		}

		return $total;
	}

	/**
	 * Retrieves the number of bookings associated with a specific customer.
	 *
	 * @param int $customerId The unique identifier of the customer whose bookings are being retrieved.
	 *
	 * @return int The total count of bookings for the specified customer.
	 */
	public function getCustomerBookings( int $customerId ) {
		return $this->model::where( 'customer_id', $customerId )->count();
	}

	/**
	 * Calculates the total spend by summing up the 'price' column of the model.
	 *
	 * @return float The total spend as a floating-point number.
	 */
	public function getTotalSpend() {
		$total = $this->model::sum( 'price' );

		return (float) $total;
	}

	/**
	 * Retrieves booking information based on the provided appointment ID.
	 * If the `$isSerialize` parameter is true and booking information is found,
	 * the customer information is unserialized and additional customer data is fetched and attached.
	 *
	 * @param int $appointmentId The ID of the appointment for which the booking information is to be retrieved.
	 * @param bool $isSerialize Optional. If true, deserializes and fetches detailed customer information. Default is false.
	 *
	 * @return mixed An object containing booking information or null if no booking is found.
	 */
	public function getBookingByAppointmentId( $appointmentId, $isSerialize = false ) {
		$customer = $this->model::where( 'appointment_id', $appointmentId )->first();
		if ( $isSerialize && $customer ) {
			$get_customer = User::find( $customer->customer_id );
			if ( ! $get_customer ) {
				return  maybe_unserialize( $customer->customer_info );
			}
			$profile                 = $get_customer->profile()->get();
			$customer->customer_info = unserialize( $customer->customer_info );
			$customer->dynamic_pricing = maybe_unserialize( $customer->dynamic_pricing );
			if ( $profile ) {
				$customer_info           = array(
					'name'       => $profile->first_name . ' ' . $profile->last_name,
					'first_name' => $profile->first_name,
					'last_name'  => $profile->last_name,
					'email'      => $get_customer->email,
					'phone'      => $profile->phone,
				);
				$customer->customer_info = $customer_info;
			}
			$customer->custom_info = maybe_unserialize( $customer->custom_info );

			return $customer;
		}

		return $this->model::where( 'appointment_id', $appointmentId )->first();
	}

	/**
	 * Retrieves the payment details for a specific customer's booking.
	 *
	 * @param int|string $customer_id The ID of the customer.
	 * @param int|string $booking_id The ID of the booking.
	 *
	 * @return Payment|null The payment record associated with the given customer and booking, or null if no record is found.
	 */
	public function getCustomerBookingPayment( $customer_id, $booking_id ) {
		return Payment::where( 'customer_id', $customer_id )->where( 'booking_id', $booking_id )->first();
	}


	/**
	 * Retrieves the payment associated with a specific booking.
	 *
	 * @param int|string $bookingId The unique identifier of the booking.
	 *
	 * @return Payment|null The payment information for the specified booking, or null if not found.
	 */
	public function getBookingPayment( $bookingId ) {
		return Payment::where( 'booking_id', $bookingId )->first();
	}

	/**
	 * Retrieves the payment details for a booking associated with a specific appointment ID.
	 *
	 * @param int|string $appointmentId The ID of the appointment.
	 *
	 * @return Payment|null The payment record associated with the booking for the given appointment ID, or null if no booking or payment is found.
	 */
	public function getBookingPaymentByAppointmentId( $appointmentId ) {
		$booking = $this->model::where( 'appointment_id', $appointmentId )->first();
		if ( $booking ) {
			return $this->getCustomerBookingPayment( $booking->customer_id, $booking->id );
		}

		return null;
	}

	public function getBookingByAppointmentIdAndCustomerId( $appointmentId, $customerId ) {
		return $this->model::where( 'appointment_id', $appointmentId )->where( 'customer_id', $customerId )->first();
	}
}
