<?php
/**
 * Customer Service
 */

namespace RadiusTheme\RadiusBooking\Services;

use RadiusTheme\RadiusBooking\Core\Container\Container;
use RadiusTheme\RadiusBooking\Core\Support\Collection;
use RadiusTheme\RadiusBooking\Helpers\SettingsHelper;
use RadiusTheme\RadiusBooking\Models\Appointment;
use RadiusTheme\RadiusBooking\Models\CustomerBooking;
use RadiusTheme\RadiusBooking\Models\Service;
use RadiusTheme\RadiusBooking\Models\User;
use RadiusTheme\RadiusBooking\Repositories\BookingRepository;
use RadiusTheme\RadiusBooking\Repositories\UserProfileRepository;
use RadiusTheme\RadiusBooking\Repositories\UserRepository;
use DateTime;
use DateTimeZone;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}
/**
 * Services/CustomerService.php
 * Business logic layer for Customer.
 */
class CustomerService {

	/**
	 * The user repository instance.
	 *
	 * @var UserRepository
	 */
	private UserRepository $userRepository;
	/**
	 * The user service instance.
	 *
	 * @var UserService
	 */
	private UserService $userService;


	private $bookingRepository;

	/**
	 * Constructor method for initializing the class with required dependencies.
	 *
	 * @param UserRepository $userRepository An instance of UserRepository to handle data operations.
	 * @param UserService $userService An instance of UserService to manage user-related functionalities.
	 *
	 * @return void
	 */
	public function __construct( UserRepository $userRepository, UserService $userService, BookingRepository $bookingRepository ) {
		$this->userRepository    = $userRepository;
		$this->userService       = $userService;
		$this->bookingRepository = $bookingRepository;
	}

	/**
	 * Resolves the customer associated with a booking.
	 *
	 * @param array $booking An array containing booking details. Expected keys are:
	 *                       - 'customer_id' (optional): The ID of the customer to validate.
	 *                       - 'customer_info' (optional): Information to find or create a customer.
	 *
	 * @return int|null Returns a valid customer ID if found or created, or null if no customer could be resolved.
	 */
	public function resolveCustomer( array $booking ): ?int {
		if ( ! empty( $booking['customer_id'] ) ) {
			return $this->validateCustomerId( $booking['customer_id'] );
		}

		return $this->findOrCreateCustomer( $booking['customer_info'] ?? array() );
	}

	/**
	 * Validates the provided customer ID by checking its existence in the repository.
	 *
	 * @param int $customer_id The ID of the customer to validate.
	 *
	 * @return int|null Returns the customer ID if valid and exists, or null if not found or invalid.
	 */
	private function validateCustomerId( int $customer_id ): ?int {
		$customer = $this->userRepository->findById( $customer_id );

		return $customer && $customer->get_id() ? $customer->get_id() : null;
	}

	/**
	 * Finds an existing customer by email or creates a new customer if none exists.
	 *
	 * @param array $customer_info An associative array containing customer details, including the required 'email' key.
	 *
	 * @return int|null Returns the ID of the existing or newly created customer, or null if the email is not provided.
	 */
	public function findOrCreateCustomer( array $customer_info ): ?int {
		if ( empty( $customer_info['email'] ) ) {
			return null;
		}

		$existing_user = $this->userRepository->findByEmail( $customer_info['email'] );
		if ( $existing_user ) {
			return $existing_user->id;
		}

		return $this->createNewCustomer( $customer_info );
	}

	/**
	 * Creates a new customer using the provided customer information.
	 *
	 * @param array $customer_info An associative array containing customer details. It may include keys such as 'first_name', 'last_name', and 'email'.
	 *
	 * @return int|null Returns the ID of the newly created customer, or null if the operation fails.
	 */
	public function createNewCustomer( array $customer_info ): ?int {
		$customer_data = array(
			'first_name' => $customer_info['first_name'] ?? '',
			'last_name'  => $customer_info['last_name'] ?? '',
			'email'      => $customer_info['email'] ?? '',
			'phone'      => $customer_info['phone'] ?? '',
			'user_type'  => 'customer',
		);

		$user_id = $this->userService->createUser( $customer_data );

		if ( $user_id && is_int( $user_id ) ) {
			$auth_settings = SettingsHelper::get_setting( 'auth' );
			if ( ! empty( $auth_settings['useWordPressUsers'] ) ) {
				$this->userService->createWpUser( $user_id, $customer_data );
			}
		}

		return $user_id;
	}

	/**
	 * Get dashboard data for a specific customer.
	 *
	 * Retrieves appointment statistics, booking history, payment information,
	 * and financial summaries for the customer portal dashboard.
	 *
	 * @param int $customer_id The customer ID to retrieve data for.
	 * @param int $page Current page number. Default 1.
	 * @param int $per_page Number of bookings per page. Default 10.
	 *
	 * @return array Dashboard data array.
	 * @since 1.0.0
	 *
	 */
	public function getDashboardData( $customer_id, $page = 1, $per_page = 10 ) {
		$customer_id = absint( $customer_id );
		$page        = max( 1, absint( $page ) );
		$per_page    = max( 1, min( 100, absint( $per_page ) ) );
		if ( ! $customer_id ) {
			return $this->getEmptyDashboardData();
		}

		// Get all bookings for statistics calculation.
		$all_bookings   = $this->getCustomerBookings( $customer_id );
		$bookings_array = ( new Collection( $all_bookings ) )->toArray();

		// Get paginated bookings.
		$paginated_bookings = $this->getPaginatedBookings( $customer_id, $page, $per_page );

		$bookings_list = array_map(
			function ( $booking ) {
				return apply_filters( 'rtrb_my_booking_item_data', (object) $booking );
			},
			is_array( $paginated_bookings['data'] ) ? $paginated_bookings['data'] : $paginated_bookings['data']->toArray()
		);

		$upcoming_list = array_map(
			function ( $booking ) {
				return apply_filters( 'rtrb_my_booking_item_data', (object) $booking );
			},
			$this->getUpcomingAppointments( $bookings_array )
		);

		return array(
			'total_appointments'     => count( $bookings_array ),
			'pending_appointments'   => $this->countByStatus( $bookings_array, 'pending' ),
			'completed_appointments' => $this->countByStatus( $bookings_array, 'completed' ),
			'confirmed_appointments' => $this->countByStatus( $bookings_array, 'confirmed' ),
			'cancelled_appointments' => $this->countByStatus( $bookings_array, 'cancelled' ),
			'total_spend'            => $this->calculateTotalSpend( $bookings_array ),
			'total_due'              => $this->calculateTotalDue( $bookings_array ),
			'total_transactions'     => $this->countCompletedTransactions( $bookings_array ),
			'bookings'               => $bookings_list,
			'pagination'             => $paginated_bookings['pagination'],
			'upcoming_appointments'  => $upcoming_list,
		);
	}

	/**
	 * Get empty dashboard data structure.
	 *
	 * Returns default values when customer ID is invalid.
	 *
	 * @return array Empty dashboard data with zero values.
	 * @since 1.0.0
	 *
	 */
	private function getEmptyDashboardData() {
		return array(
			'total_appointments'     => 0,
			'pending_appointments'   => 0,
			'completed_appointments' => 0,
			'confirmed_appointments' => 0,
			'cancelled_appointments' => 0,
			'total_spend'            => 0.00,
			'total_due'              => 0.00,
			'total_transactions'     => 0,
			'bookings'               => array(),
			'pagination'             => $this->getEmptyPagination(),
			'upcoming_appointments'  => array(),
		);
	}

	/**
	 * Get empty pagination structure.
	 *
	 * @return array Empty pagination data.
	 * @since 1.0.0
	 *
	 */
	private function getEmptyPagination() {
		return array(
			'current_page' => 1,
			'per_page'     => 10,
			'total_items'  => 0,
			'total_pages'  => 0,
			'has_previous' => false,
			'has_next'     => false,
		);
	}

	/**
	 * Get paginated customer bookings.
	 *
	 * Retrieves bookings with pagination metadata.
	 *
	 * @param int $customer_id The customer ID.
	 * @param int $page Current page number.
	 * @param int $per_page Number of items per page.
	 *
	 * @return array Array containing 'data' and 'pagination' keys.
	 * @since 1.0.0
	 *
	 */
	private function getPaginatedBookings( $customer_id, $page, $per_page ) {
		$prefix = radius_table_prefix();
		$offset = ( $page - 1 ) * $per_page;

		// Get total count.
		$total_items = $this->getCustomerBookingsCount( $customer_id );
		$total_pages = (int) ceil( $total_items / $per_page );

		// Get paginated results.
		$bookings = CustomerBooking::query()
		                           ->leftJoin(
			                           'radius_booking_appointments',
			                           'radius_booking_appointments.id',
			                           '=',
			                           'radius_booking_customer_bookings.appointment_id'
		                           )
		                           ->leftJoin(
			                           'radius_booking_services',
			                           'radius_booking_services.id',
			                           '=',
			                           'radius_booking_appointments.service_id'
		                           )
		                           ->leftJoin(
			                           'radius_booking_users',
			                           'radius_booking_users.id',
			                           '=',
			                           'radius_booking_appointments.employee_id'
		                           )
		                           ->leftJoin(
			                           'radius_booking_user_profiles',
			                           'radius_booking_user_profiles.user_id',
			                           '=',
			                           'radius_booking_users.id'
		                           )
		                           ->leftJoin(
			                           'radius_booking_payments',
			                           'radius_booking_payments.booking_id',
			                           '=',
			                           'radius_booking_customer_bookings.id'
		                           )
		                           ->leftJoin(
			                           'radius_booking_meeting_types',
			                           'radius_booking_meeting_types.id',
			                           '=',
			                           'radius_booking_appointments.meeting_type_id'
		                           )
		                           ->leftJoin(
			                           'radius_booking_events',
			                           'radius_booking_events.id',
			                           '=',
			                           'radius_booking_appointments.event_id'
		                           )
		                           ->where( $prefix . 'customer_bookings.customer_id', $customer_id )
		                           ->select(
			                           $prefix . 'appointments.id as appointment_id',
			                           $prefix . 'appointments.status as appointment_status',
			                           $prefix . 'appointments.appointment_date',
			                           $prefix . 'appointments.start_time',
			                           $prefix . 'appointments.end_time',
			                           $prefix . 'appointments.service_id',
			                           $prefix . 'appointments.employee_id',
			                           $prefix . 'appointments.booking_type',
			                           $prefix . 'services.name as service_name',
			                           $prefix . 'meeting_types.name as meeting_type_name',
			                           $prefix . 'events.name as event_name',
			                           $prefix . 'user_profiles.first_name as employee_first_name',
			                           $prefix . 'user_profiles.last_name as employee_last_name',
			                           $prefix . 'payments.id as payment_id',
			                           $prefix . 'payments.transaction_id',
			                           $prefix . 'payments.payment_method',
			                           $prefix . 'payments.amount as paid_amount',
			                           $prefix . 'payments.total_amount',
			                           $prefix . 'payments.due_amount',
			                           $prefix . 'payments.status as payment_status',
			                           $prefix . 'payments.paid_at',
			                           $prefix . 'payments.coupon_code',
			                           $prefix . 'payments.discount_amount',
			                           $prefix . 'payments.tax_rate',
			                           $prefix . 'payments.tax_amount',
			                           $prefix . 'customer_bookings.*'
		                           )
		                           ->orderBy( $prefix . 'appointments.appointment_date', 'DESC' )
		                           ->limit( $per_page )
		                           ->offset( $offset )
		                           ->get();

		return array(
			'data'       => $bookings,
			'pagination' => array(
				'current_page' => $page,
				'per_page'     => $per_page,
				'total_items'  => $total_items,
				'total_pages'  => $total_pages,
				'has_previous' => $page > 1,
				'has_next'     => $page < $total_pages,
			),
		);
	}

	/**
	 * Get total count of customer bookings.
	 *
	 * @param int $customer_id The customer ID.
	 *
	 * @return int Total number of bookings.
	 * @since 1.0.0
	 *
	 */
	private function getCustomerBookingsCount( $customer_id ) {
		$prefix = radius_table_prefix();

		return CustomerBooking::query()
		                      ->where( $prefix . 'customer_bookings.customer_id', $customer_id )
		                      ->count();
	}

	/**
	 * Get customer bookings with related data.
	 *
	 * Retrieves all bookings for a customer with joined appointment,
	 * service, employee, and payment data.
	 *
	 * @param int $customer_id The customer ID.
	 *
	 * @return array Array of booking records.
	 * @since 1.0.0
	 *
	 */
	private function getCustomerBookings( $customer_id ) {
		$prefix = radius_table_prefix();

		return CustomerBooking::query()
		                      ->leftJoin(
			                      'radius_booking_appointments',
			                      'radius_booking_appointments.id',
			                      '=',
			                      'radius_booking_customer_bookings.appointment_id'
		                      )
		                      ->leftJoin(
			                      'radius_booking_services',
			                      'radius_booking_services.id',
			                      '=',
			                      'radius_booking_appointments.service_id'
		                      )
		                      ->leftJoin(
			                      'radius_booking_users',
			                      'radius_booking_users.id',
			                      '=',
			                      'radius_booking_appointments.employee_id'
		                      )
		                      ->leftJoin(
			                      'radius_booking_user_profiles',
			                      'radius_booking_user_profiles.user_id',
			                      '=',
			                      'radius_booking_users.id'
		                      )
		                      ->leftJoin(
			                      'radius_booking_payments',
			                      'radius_booking_payments.booking_id',
			                      '=',
			                      'radius_booking_customer_bookings.id'
		                      )
		                      ->leftJoin(
			                      'radius_booking_meeting_types',
			                      'radius_booking_meeting_types.id',
			                      '=',
			                      'radius_booking_appointments.meeting_type_id'
		                      )
		                      ->leftJoin(
			                      'radius_booking_events',
			                      'radius_booking_events.id',
			                      '=',
			                      'radius_booking_appointments.event_id'
		                      )
		                      ->where( $prefix . 'customer_bookings.customer_id', $customer_id )
		                      ->select(
			                      $prefix . 'appointments.id as appointment_id',
			                      $prefix . 'appointments.status as appointment_status',
			                      $prefix . 'appointments.appointment_date',
			                      $prefix . 'appointments.start_time',
			                      $prefix . 'appointments.end_time',
			                      $prefix . 'appointments.service_id',
			                      $prefix . 'appointments.employee_id',
			                      $prefix . 'appointments.booking_type',
			                      $prefix . 'services.name as service_name',
			                      $prefix . 'meeting_types.name as meeting_type_name',
			                      $prefix . 'events.name as event_name',
			                      $prefix . 'user_profiles.first_name as employee_first_name',
			                      $prefix . 'user_profiles.last_name as employee_last_name',
			                      $prefix . 'payments.id as payment_id',
			                      $prefix . 'payments.transaction_id',
			                      $prefix . 'payments.payment_method',
			                      $prefix . 'payments.amount as paid_amount',
			                      $prefix . 'payments.total_amount',
			                      $prefix . 'payments.due_amount',
			                      $prefix . 'payments.status as payment_status',
			                      $prefix . 'payments.paid_at',
			                      $prefix . 'payments.coupon_code',
			                      $prefix . 'payments.discount_amount',
			                      $prefix . 'payments.tax_rate',
			                      $prefix . 'payments.tax_amount',
			                      $prefix . 'customer_bookings.*'
		                      )
		                      ->orderBy( $prefix . 'appointments.appointment_date', 'DESC' )
		                      ->get();
	}

	/**
	 * Count bookings by appointment status.
	 *
	 * @param array $bookings Array of booking records.
	 * @param string $status The status to count.
	 *
	 * @return int Count of bookings with the specified status.
	 * @since 1.0.0
	 *
	 */
	private function countByStatus( $bookings, $status ) {
		$statuses      = array_column( $bookings, 'appointment_status' );
		$status_counts = array_count_values( array_filter( $statuses, 'is_string' ) );

		return $status_counts[ $status ] ?? 0;
	}

	/**
	 * Calculate total amount spent by customer.
	 *
	 * Sums paid amounts for completed, paid, and partial payment transactions.
	 *
	 * @param array $bookings Array of booking records.
	 *
	 * @return float Total spent amount rounded to 2 decimal places.
	 * @since 1.0.0
	 *
	 */
	private function calculateTotalSpend( $bookings ) {
		$completed_statuses = array( 'completed', 'paid', 'partial_payment' );
		$payment_statuses   = array_column( $bookings, 'payment_status' );
		$paid_amounts       = array_column( $bookings, 'paid_amount' );

		$total = array_sum(
			array_map(
				function ( $amount, $status ) use ( $completed_statuses ) {
					return in_array( $status, $completed_statuses, true ) ? (float) $amount : 0;
				},
				$paid_amounts,
				$payment_statuses
			)
		);

		return round( $total, 2 );
	}

	/**
	 * Calculate total due amount for customer.
	 *
	 * Sums due amounts excluding refunded and failed transactions.
	 *
	 * @param array $bookings Array of booking records.
	 *
	 * @return float Total due amount rounded to 2 decimal places.
	 * @since 1.0.0
	 *
	 */
	private function calculateTotalDue( $bookings ) {
		$excluded_statuses = array( 'refunded', 'failed' );
		$payment_statuses  = array_column( $bookings, 'payment_status' );
		$due_amounts       = array_column( $bookings, 'due_amount' );

		$total = array_sum(
			array_map(
				function ( $amount, $status ) use ( $excluded_statuses ) {
					return ! in_array( $status, $excluded_statuses, true ) ? (float) $amount : 0;
				},
				$due_amounts,
				$payment_statuses
			)
		);

		return round( $total, 2 );
	}

	/**
	 * Count completed transactions.
	 *
	 * Counts transactions with completed, paid, or partial payment status.
	 *
	 * @param array $bookings Array of booking records.
	 *
	 * @return int Number of completed transactions.
	 * @since 1.0.0
	 *
	 */
	private function countCompletedTransactions( $bookings ) {
		$completed_statuses = array( 'completed', 'paid', 'partial_payment' );
		$payment_statuses   = array_column( $bookings, 'payment_status' );

		return count(
			array_filter(
				$payment_statuses,
				function ( $status ) use ( $completed_statuses ) {
					return in_array( $status, $completed_statuses, true );
				}
			)
		);
	}

	/**
	 * Get upcoming appointments within next 7 days.
	 *
	 * Filters and sorts appointments that are pending or confirmed
	 * and scheduled within the next week.
	 *
	 * @param array $bookings Array of booking records.
	 *
	 * @return array Filtered and sorted upcoming appointments.
	 * @since 1.0.0
	 *
	 */
	private function getUpcomingAppointments( $bookings ) {
		$today           = wp_date( 'Y-m-d' );
		$one_week_later  = wp_date( 'Y-m-d', strtotime( '+7 days' ) );
		$active_statuses = array( 'pending', 'confirmed' );

		$upcoming = array_filter(
			$bookings,
			function ( $booking ) use ( $today, $one_week_later, $active_statuses ) {
				$appointment_date = $booking['appointment_date'] ?? '';
				$status           = $booking['appointment_status'] ?? '';

				return $appointment_date >= $today
				       && $appointment_date <= $one_week_later
				       && in_array( $status, $active_statuses, true );
			}
		);

		return $this->sortAppointmentsByDateTime( array_values( $upcoming ) );
	}

	/**
	 * Sort appointments by date and time ascending.
	 *
	 * @param array $appointments Array of appointment records.
	 *
	 * @return array Sorted appointments.
	 * @since 1.0.0
	 *
	 */
	private function sortAppointmentsByDateTime( $appointments ) {
		usort(
			$appointments,
			function ( $a, $b ) {
				$date_a = $a['appointment_date'] . ' ' . ( $a['start_time'] ?? '00:00:00' );
				$date_b = $b['appointment_date'] . ' ' . ( $b['start_time'] ?? '00:00:00' );

				return strcmp( $date_a, $date_b );
			}
		);

		return $appointments;
	}

	/**
	 * Cancel an appointment for a customer.
	 *
	 * Validates cancellation permissions, checks minimum cancellation time requirements,
	 * and updates the appointment status if all conditions are met.
	 *
	 * @param int $appointment_id The ID of the appointment to cancel.
	 * @param int $customer_id The ID of the customer requesting cancellation.
	 * @param string $cancellation_reason The reason provided for cancellation.
	 *
	 * @return array {
	 *     Cancellation result.
	 *
	 * @type bool $available Whether the cancellation was successful.
	 * @type string $reason The reason code (only on failure).
	 * @type string $message Human-readable result message.
	 * }
	 * @throws \Exception If appointment not found or doesn't belong to customer.
	 */
	public function cancelAppointment( $appointment_id, $customer_id, $cancellation_reason ) {
		$booking = $this->bookingRepository->getBookingByAppointmentId( $appointment_id, $customer_id );

		if ( ! $booking ) {
			throw new \Exception( 'Appointment not found or does not belong to the customer.' );
		}

		$customer_cancel_settings = SettingsHelper::get_setting( 'customer' );
		$allow_cancel             = $customer_cancel_settings['allowCancel'] ?? false;

		if ( ! $allow_cancel ) {
			return array(
				'available' => false,
				'reason'    => 'not_allowed',
				'message'   => __( 'Booking cancellation is not allowed.', 'radius-booking' ),
			);
		}

		$appointment      = Appointment::find( $booking->appointment_id );
		$appointment_date = $appointment->appointment_date();
		$appointment_time = $appointment->start_time();
		$booking_type     = $appointment->booking_type();

		// Meetings and events don't have per-service min cancel time.
		if ( 'meeting' === $booking_type || 'event' === $booking_type ) {
			$service_min_cancel_time = 'disabled';
		} else {
			$appointment_service     = $appointment->get_service()->get();
			$service                 = Service::find( $appointment_service->id );
			$service_min_cancel_time = $service ? $service->get_min_cancel_time() : 'disabled';
		}

		// Check minimum cancellation time if enabled.
		if ( $service_min_cancel_time !== 'disabled' ) {
			$validation_result = $this->validateMinimumCancelTime(
				$appointment,
				$appointment_date,
				$appointment_time,
				$service_min_cancel_time
			);

			if ( ! $validation_result['valid'] ) {
				return array(
					'available' => false,
					'reason'    => 'minimum_time',
					'message'   => $validation_result['message'],
				);
			}
		}

		// All checks passed - cancel the appointment.
		$this->updateAppointmentStatus( $appointment, $cancellation_reason );

		return array(
			'available' => true,
			'message'   => __( 'Appointment cancelled successfully.', 'radius-booking' ),
		);
	}

	/**
	 * Validate minimum cancellation time requirement.
	 *
	 * Checks if the appointment can be cancelled based on the service's
	 * minimum cancellation time setting and the employee's timezone.
	 *
	 * @param Appointment $appointment The appointment to validate.
	 * @param string $appointment_date The appointment date (Y-m-d format).
	 * @param string $appointment_time The appointment start time (H:i format).
	 * @param int $service_min_cancel_time Minimum cancel time in seconds.
	 *
	 * @return array {
	 *     Validation result.
	 *
	 * @type bool $valid Whether the cancellation time requirement is met.
	 * @type string $message Error message if validation fails.
	 * }
	 */
	private function validateMinimumCancelTime( $appointment, $appointment_date, $appointment_time, $service_min_cancel_time ) {
		$employee_id = $appointment->get_employee_id() ?? null;
		$employee    = $employee_id ? $this->userRepository->get_profile( $employee_id ) : null;

		// Convert seconds to minutes.
		$minimum_minutes = $service_min_cancel_time / 60;

		// Determine timezone - use employee's timezone or fall back to site timezone.
		$timezone = ( $employee && ! empty( $employee->timezone ) )
			? new \DateTimeZone( $employee->timezone )
			: wp_timezone();

		$current_datetime     = new \DateTime( 'now', $timezone );
		$appointment_datetime = new \DateTime(
			$appointment_date . ' ' . $appointment_time,
			$timezone
		);

		// Calculate the minimum required time before appointment.
		$minimum_required_datetime = clone $current_datetime;
		$minimum_required_datetime->modify( "+{$minimum_minutes} minutes" );

		$cancellation_deadline = clone $appointment_datetime;
		$cancellation_deadline->modify( "-{$minimum_minutes} minutes" );
		if ( $appointment_datetime->getTimestamp() < $minimum_required_datetime->getTimestamp() ) {
			$time_text = $this->formatMinutesAsReadableTime( $minimum_minutes );

			return array(
				'valid'   => false,
				'message' => sprintf(
				/* translators: %1$s: Minimum time required (e.g., "2 hours and 30 minutes"), %2$s: Appointment date/time, %3$s: Cancellation deadline */
					__( 'Cancellation not allowed. This service requires %1$s advance notice for cancellations. Your appointment is scheduled for %2$s, and the cancellation deadline was %3$s.', 'radius-booking' ),
					$time_text,
					$appointment_datetime->format( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ),
					$cancellation_deadline->format( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) )
				),
			);
		}

		return array( 'valid' => true );
	}

	/**
	 * Format minutes as human-readable time string.
	 *
	 * Converts a number of minutes into a readable format like
	 * "2 hours and 30 minutes" or "45 minutes".
	 *
	 * @param int $minutes Total minutes to format.
	 *
	 * @return string Formatted time string.
	 */
	private function formatMinutesAsReadableTime( $minutes ) {
		$hours = floor( $minutes / 60 );
		$mins  = $minutes % 60;

		$parts = array();

		if ( $hours > 0 ) {
			$parts[] = sprintf(
			/* translators: %d: Number of hours */
				_n( '%d hour', '%d hours', $hours, 'radius-booking' ),
				$hours
			);
		}

		if ( $mins > 0 ) {
			$parts[] = sprintf(
			/* translators: %d: Number of minutes */
				_n( '%d minute', '%d minutes', $mins, 'radius-booking' ),
				$mins
			);
		}

		if ( empty( $parts ) ) {
			return __( '0 minutes', 'radius-booking' );
		}

		/* translators: Used to join hours and minutes, e.g., "2 hours and 30 minutes" */

		return implode( __( ' and ', 'radius-booking' ), $parts );
	}

	/**
	 * Update appointment status to cancelled.
	 *
	 * @param Appointment $appointment The appointment to cancel.
	 * @param string $cancellation_reason The reason for cancellation.
	 *
	 * @return void
	 */
	private function updateAppointmentStatus( $appointment, $cancellation_reason ) {
		$appointment->status              = 'cancelled';
		$appointment->cancellation_reason = $cancellation_reason;
		$appointment->save();
	}

	public function getProfileData( $user_id ) {
		$user_profile                  = (array) $this->userRepository->get_profile( $user_id );
		$user_profile['image_full_path'] =  $this->userRepository->getImageUrl( $user_profile['id'] );
		$user                          = (array) User::where( 'id', $user_id )->first();

		return array_merge( $user_profile, $user );
	}

	public function updateProfileData( $request ) {
		$user_id         = $request->get_param( 'user_id' );
		$user            = $this->userRepository->find( $user_id );
		$data            = $request->get_params();
		$data['user_id'] = $user_id;
		$user->update( $request->get_params() );
		$user_profile = Container::resolve( UserProfileRepository::class );
		$user_profile->updateProfile( $user_id, $data );

		return $this->getProfileData( $user_id );
	}

	public function changePassword( $request ) {
		$employee_id      = $request->get_param( 'employee_id' );
		$current_password = $request->get_param( 'current_password' );
		$new_password     = $request->get_param( 'new_password' );

		$user_service = Container::resolve( UserService::class );
		$result       = $user_service->updatePassword( $employee_id, $current_password, $new_password );

		return $result;
	}


}
