<?php
/**
 * RadiusBooking API Route Registrar
 *
 * This class is responsible for registering API routes dynamically with the WordPress REST API.
 * It supports CRUD operations and allows for middleware to be applied globally or per route.
 *
 * @package RadiusTheme\RadiusBooking\Core\Api\Routes
 */
namespace RadiusTheme\RadiusBooking\Resources;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}
use RadiusTheme\RadiusBooking\Abstracts\BaseResource;
use RadiusTheme\RadiusBooking\Core\Container\Container;
use RadiusTheme\RadiusBooking\Models\Service;
use RadiusTheme\RadiusBooking\Repositories\AppointmentIntegrationRepository;
use RadiusTheme\RadiusBooking\Repositories\AppointmentRepository;
use RadiusTheme\RadiusBooking\Repositories\BookingRepository;
use RadiusTheme\RadiusBooking\Repositories\LocationRepository;
use RadiusTheme\RadiusBooking\Repositories\ServiceRepository;
use RadiusTheme\RadiusBooking\Repositories\UserProfileRepository;
use RadiusTheme\RadiusBooking\Repositories\UserRepository;

/**
 * AppointmentResource
 *
 * Transforms Appointment model instances into API-friendly arrays.
 *
 * @package RadiusTheme\RadiusBooking\Resources
 */
class AppointmentResource extends BaseResource {

	/**
	 * Transform an Appointment model into an array suitable for API responses.
	 *
	 * @param object $appointment The Appointment model instance.
	 *
	 * @return array Transformed appointment data.
	 */
	public function transform( $appointment ): array {
		$data = array(
			'id'                 => $appointment->id,
			'employee_id'        => $appointment->employee_id,
			'employee_name'      => $this->getEmployeeName( $appointment->employee_id ),
			'employee_email'     => $this->getEmployee( $appointment->employee_id ) ? $this->getEmployee( $appointment->employee_id )->email : '',
			'employee_phone'     => $this->getEmployeePhone( $appointment->employee_id ),
			'employee_image'     => $this->getEmployeeImage( $appointment->employee_id ),
			'service_id'         => $appointment->service_id,
			'service_name'       => $this->getServiceName( $appointment->service_id ),
			'location_id'        => $appointment->location_id,
			'appointment_date'   => $appointment->appointment_date,
			'start_time'         => $appointment->start_time,
			'end_time'           => $appointment->end_time,
			'status'             => $appointment->status,
			'notify_customer'    => $appointment->notify_customer,
			'notes'              => $appointment->notes,
			'created_at'         => $appointment->created_at,
			'updated_at'         => $appointment->updated_at,
			'customer'           => ( new BookingRepository() )->getBookingByAppointmentId( $appointment->id, true ),
			'payment'            => ( new BookingRepository() )->getBookingPaymentByAppointmentId( $appointment->id ),
			'time'               => $this->getTime( $appointment->start_time, $appointment->end_time, $appointment->id, $appointment->service_id, $appointment->employee_id ),
			'currency_symbol'    => get_rtrb_currency_symbol(),
			'currency'           => array(
				'currency_symbol' => get_rtrb_currency_symbol(),
				'currency'        => get_rtrb_currency(),
			),
			'child_appointments' => ( new AppointmentRepository() )->getChildAppointments( $appointment->id ),
			'parent_appointment' => ( new AppointmentRepository() )->getParentAppointment( $appointment->id ),
		);
		if($appointment->location_id){
			$data['location_info']      = ( new LocationRepository() )->getLocationData( $appointment->location_id );
		}

		$data['meeting_link']      = $this->getMeetingLink( $appointment->id );
		$data['booking_type']      = $appointment->booking_type ?? 'service_booking';
		$data['meeting_type_id']   = $appointment->meeting_type_id ?? null;
		$data['meeting_type_name'] = $this->getMeetingTypeName( $appointment->meeting_type_id ?? null );
		$data['event_id']          = $appointment->event_id ?? null;
		$data['event_name']        = $this->getEventName( $appointment->event_id ?? null );

		// Include event registration ticket details for event bookings.
		if ( 'event' === ( $appointment->booking_type ?? '' ) ) {
			$data['event_tickets'] = $this->getEventTickets( $appointment->id );
		}

		return apply_filters( 'rtrb_appointment_resource_data', $data, $appointment );
	}

	/**
	 * Retrieves the name of a service based on a given service ID.
	 *
	 * @param int|string $serviecId The unique identifier of the service.
	 *
	 * @return string|null The name of the service if found, or null if the service does not exist.
	 */
	public function getServiceName( $serviecId ) {
		$service = Container::resolve( ServiceRepository::class );
		if ( $service->exists( $serviecId ) ) {
			$service = $service->find( $serviecId );

			return $service->get_name();
		}
	}

	/**
	 * Retrieves employee information based on a given employee ID.
	 *
	 * @param int|string $employee_id The unique identifier of the employee.
	 *
	 * @return mixed The employee data if found, or null if the employee does not exist.
	 */
	public function getEmployee( $employee_id ) {
		$employee = Container::resolve( UserRepository::class );
		if ( $employee->exists( $employee_id ) ) {
			return $employee->find( $employee_id );
		}

		return null;
	}

	/**
	 * Retrieves the full name of an employee based on a given employee ID.
	 *
	 * @param int|string $employeeId The unique identifier of the employee.
	 *
	 * @return string The full name of the employee if found, or an empty string if the employee does not exist.
	 */
	public function getEmployeeName( $employeeId ) {
		$employee = Container::resolve( UserProfileRepository::class );
		if ( $employee->exists( $employeeId ) ) {
			$employee = $employee->find( $employeeId );

			return $employee->fullName();
		}

		return '';
	}

	/**
	 * Retrieves the phone number for a specific employee based on the given employee ID.
	 *
	 * @param int|string $employeeId The unique identifier of the employee.
	 *
	 * @return string The phone number of the employee if found, otherwise an empty string.
	 */
	public function getEmployeePhone( $employeeId ) {
		$employee = Container::resolve( UserProfileRepository::class );
		if ( $employee->exists( $employeeId ) ) {
			$employee = $employee->find( $employeeId );

			return $employee->phone ?? '';
		}

		return '';
	}

	/**
	 * Retrieves the image URL for a specific employee based on the given employee ID.
	 *
	 * @param mixed $employeeId The unique identifier of the employee whose image URL is to be retrieved.
	 *
	 * @return string The image URL of the employee if found, otherwise an empty string.
	 */
	public function getEmployeeImage( $employeeId ) {
		$employee = Container::resolve( UserProfileRepository::class );
		if ( $employee->exists( $employeeId ) ) {
			$employee = $employee->find( $employeeId );

			return $employee->getImageUrl();
		}

		return '';
	}

	/**
	 * Retrieves time-related details for a booking based on appointment and service information.
	 *
	 * @param string $startTime The start time of the booking.
	 * @param string $endTime The end time of the booking.
	 * @param int|string $appointment_id The unique identifier of the appointment.
	 * @param int|string $service_id The unique identifier of the service.
	 * @param int|string $employee_id The unique identifier of the employee.
	 *
	 * @return array An array containing calculated time details, including start time, end time, duration, availability status, current capacity, and maximum capacity.
	 */
	/**
	 * Retrieves the meeting link (Zoom / Google Meet) for an appointment.
	 *
	 * @param int|string $appointment_id The appointment ID.
	 *
	 * @return array|null Meeting link data or null.
	 */
	public function getMeetingLink( $appointment_id ) {
		$repo         = Container::resolve( AppointmentIntegrationRepository::class );
		$integrations = $repo->getByAppointment( $appointment_id );

		if ( empty( $integrations ) ) {
			return null;
		}

		$links = array();
		foreach ( $integrations as $integration ) {
			$join_url = $integration->join_url ?? $integration->meeting_url ?? '';
			if ( ! empty( $join_url ) ) {
				$links[] = array(
					'provider'  => $integration->provider ?? 'zoom',
					'join_url'  => $join_url,
					'start_url' => $integration->start_url ?? '',
					'status'    => $integration->status ?? 'created',
				);
			}
		}

		// Return single object for backwards compat, or null.
		return ! empty( $links ) ? $links[0] : null;
	}

	/**
	 * Get the meeting type name by ID.
	 *
	 * @param int|null $meeting_type_id The meeting type ID.
	 *
	 * @return string|null
	 */
	private function getMeetingTypeName( $meeting_type_id ) {
		if ( ! $meeting_type_id ) {
			return null;
		}
		$mt = \RadiusTheme\RadiusBooking\Models\MeetingType::find( $meeting_type_id );
		return $mt ? $mt->get_name() : null;
	}

	/**
	 * Get the event name by ID.
	 *
	 * @param int|null $event_id The event ID.
	 *
	 * @return string|null
	 */
	private function getEventName( $event_id ) {
		if ( ! $event_id ) {
			return null;
		}
		$event = \RadiusTheme\RadiusBooking\Models\Event::find( $event_id );
		return $event ? $event->get_name() : null;
	}

	/**
	 * Get event registration ticket details for an appointment.
	 *
	 * @param int $appointment_id The appointment ID.
	 *
	 * @return array
	 */
	private function getEventTickets( $appointment_id ) {
		$registrations = \RadiusTheme\RadiusBooking\Models\EventRegistration::where( 'appointment_id', $appointment_id )->get();
		$tickets       = array();

		// Build session name map from the first registration's event.
		$session_map = array();
		if ( ! empty( $registrations ) ) {
			$first_reg = $registrations[0];
			$event_id  = $first_reg->event_id ?? 0;
			if ( $event_id ) {
				$all_sessions = \RadiusTheme\RadiusBooking\Models\EventSession::where( 'event_id', (int) $event_id )->get();
				foreach ( $all_sessions as $s ) {
					$session_map[ (int) $s->id ] = $s->name ?? '';
				}
			}
		}

		foreach ( $registrations as $reg ) {
			$tid         = (int) ( $reg->ticket_type_id ?? 0 );
			$ticket_type = $tid > 0 ? \RadiusTheme\RadiusBooking\Models\EventTicketType::find( $tid ) : null;

			// Parse session IDs from attendee_info JSON.
			$attendee_data = $reg->attendee_info ?? array();
			if ( is_string( $attendee_data ) ) {
				$attendee_data = json_decode( $attendee_data, true ) ?: array();
			}
			$session_ids   = $attendee_data['sessions'] ?? array();
			$session_names = array();
			foreach ( $session_ids as $sid ) {
				$session_names[] = $session_map[ (int) $sid ] ?? "Session #{$sid}";
			}

			$tickets[] = array(
				'ticket_type_id'         => $tid,
				'ticket_name'            => $ticket_type ? $ticket_type->name : 'Unknown',
				'ticket_type'            => $ticket_type ? ( $ticket_type->ticket_type ?? 'paid' ) : 'paid',
				'quantity'               => (int) ( $reg->quantity ?? 1 ),
				'price'                  => $ticket_type ? (float) $ticket_type->price : 0,
				'registration_number'    => $reg->registration_number ?? null,
				'status'                 => $reg->status ?? 'confirmed',
				'check_in_token'         => $reg->check_in_token ?? null,
				'checked_in_at'          => $reg->checked_in_at ?? null,
				'selected_sessions'      => $session_ids,
				'selected_session_names' => $session_names,
			);
		}

		return $tickets;
	}

	public function getTime( $startTime, $endTime, $appointment_id, $service_id, $employee_id ) {
		$customer = ( new BookingRepository() )->getBookingByAppointmentId( $appointment_id );
		$service  = Container::resolve( ServiceRepository::class );
		if ( $service->exists( $service_id ) ) {
			$service = $service->getAssignServices( $service_id, $employee_id );
		}

		return array(
			'start_time'       => $startTime,
			'end_time'         => $endTime,
			'duration_minutes' => isset( $customer->duration ) ? intval( $customer->duration ) / 60 : 0,
			'is_available'     => true,
			'current_capacity' => 1,
			'max_capacity'     => $service->max_capacity ?? 1,
		);
	}
}
