<?php
/**
 * RadiusBooking Appointment Model
 *
 * This model represents the appointments in the system and defines
 * its database table, fillable attributes, data casting, validation rules,
 * and relationships to other models.
 *
 * @package RadiusTheme\RadiusBooking\Models
 */

namespace RadiusTheme\RadiusBooking\Models;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}
use RadiusTheme\RadiusBooking\Abstracts\BaseModel;
use RadiusTheme\RadiusBooking\Core\ORM\QueryBuilder;
use RadiusTheme\RadiusBooking\Core\Support\Collection;

/**
 * Class Appointment
 *
 * Represents an appointment record in the `radius_booking_appointments` table.
 *
 * @property int $id
 * @property int $user_id
 * @property int $service_id
 * @property string $appointment_date
 * @property string $start_time
 * @property string|null $end_time
 * @property string $status
 * @property string|null $notes
 */
class Appointment extends BaseModel {

	/**
	 * The table associated with the model.
	 *
	 * @var string
	 */
	protected string $table = 'radius_booking_appointments';

	/**
	 * The attributes that are mass assignable.
	 *
	 * @var array
	 */
	protected array $fillable = array(
		'employee_id',
		'service_id',
		'appointment_date',
		'start_time',
		'end_time',
		'status',
		'location_id',
		'notify_customer',
		'notes',
		'parent_id',
		'cancellation_reason',
		'booking_type',
		'meeting_type_id',
		'event_id',
	);

	/**
	 * The attributes that should be cast to specific types.
	 *
	 * @var array
	 */
	protected array $casts = array(
		'start_time'      => 'time',
		'end_time'        => 'time',
		'employee_id'     => 'integer',
		'service_id'      => 'integer',
		'status'          => 'string',
		'booking_type'    => 'string',
		'meeting_type_id' => 'integer',
		'event_id'        => 'integer',
	);

	/**
	 * Whether soft deletes are enabled for this model.
	 *
	 * @var bool
	 */
	protected bool $softDeletes = true;

	/**
	 * Get the user that owns the appointment.
	 *
	 * @return \RadiusTheme\RadiusBooking\Core\ORM\Relations\BelongsTo
	 */
	public function user() {
		return $this->belongsTo( User::class );
	}

	/**
	 * Get the service associated with the appointment.
	 *
	 * @return \RadiusTheme\RadiusBooking\Core\ORM\Relations\BelongsTo
	 */
	public function service() {
		return $this->belongsTo( Service::class );
	}

	/**
	 * Set default values before creating the appointment.
	 *
	 * @return void
	 */
	protected function onCreating(): void {
		if ( empty( $this->status ) ) {
			$this->status = 'pending';
		}
	}

	/**
	 * Scope a query to only include pending appointments.
	 *
	 * @return QueryBuilder
	 */
	public static function pending(): QueryBuilder {
		return static::where( 'status', 'pending' );
	}

	/**
	 * Scope a query to only include confirmed appointments.
	 *
	 * @return QueryBuilder
	 */
	public static function confirmed(): QueryBuilder {
		return static::where( 'status', 'confirmed' );
	}

	/**
	 * Scope a query to only include completed appointments.
	 *
	 * @return QueryBuilder
	 */
	public function get_id() {
		return $this->attributes['id'] ?? null;
	}

	/**
	 * Getters for appointment attributes.
	 */
	public function employee_id() {
		return $this->attributes['employee_id'] ?? null;
	}

	/**
	 * Get the service ID associated with the current appointment.
	 *
	 * @since 1.0.0
	 *
	 * @return int|null The service ID if set, otherwise null.
	 */
	public function service_id() {
		return $this->attributes['service_id'] ?? null;
	}

	/**
	 * Get the appointment date of the current record.
	 *
	 * @since 1.0.0
	 *
	 * @return string|null The appointment date if set, otherwise null.
	 */
	public function appointment_date() {
		return $this->attributes['appointment_date'] ?? null;
	}

	/**
	 * Get the start time of the current appointment.
	 *
	 * @since 1.0.0
	 *
	 * @return string|null The start time if set, otherwise null.
	 */
	public function start_time() {
		return $this->attributes['start_time'] ?? null;
	}

	/**
	 * Get the end time of the current appointment.
	 *
	 * @since 1.0.0
	 *
	 * @return string|null The end time if set, otherwise null.
	 */
	public function end_time() {
		return $this->attributes['end_time'] ?? null;
	}

	/**
	 * Get the status of the current appointment.
	 *
	 * @since 1.0.0
	 *
	 * @return string|null The status if set, otherwise null.
	 */
	public function status() {
		return $this->attributes['status'] ?? null;
	}

	/**
	 * Get the notes for the current appointment.
	 *
	 * @since 1.0.0
	 *
	 * @return string|null The notes if set, otherwise null.
	 */
	public function notes() {
		return $this->attributes['notes'] ?? null;
	}

	/**
	 * Get the cancellation reason for the current appointment.
	 *
	 * @since 1.0.0
	 *
	 * @return string|null The cancellation reason if set, otherwise null.
	 */
	public function cancellation_reason() {
		return $this->attributes['cancellation_reason'] ?? null;
	}

	/**
	 * Get the location ID for the current record.
	 *
	 * @since 1.0.0
	 *
	 * @return int|null The location ID if set, otherwise null.
	 */
	public function location_id() {
		return $this->attributes['location_id'] ?? null;
	}

	/**
	 * Get the notify_customer flag for the current record.
	 *
	 * Indicates whether the customer should be notified.
	 *
	 * @since 1.0.0
	 *
	 * @return bool|null True if customer should be notified, false or null otherwise.
	 */
	public function notify_customer() {
		return $this->attributes['notify_customer'] ?? null;
	}
	/**
	 * Get the parent ID of the current record.
	 *
	 * @since 1.0.0
	 *
	 * @return int|null The parent ID if set, otherwise null.
	 */
	public function parent_id() {
		return $this->attributes['parent_id'] ?? null;
	}

	/**
	 * Get the meeting type associated with this appointment.
	 *
	 * @since 1.2.0
	 *
	 * @return \RadiusTheme\RadiusBooking\Core\ORM\Relations\BelongsTo
	 */
	public function meetingType() {
		return $this->belongsTo( MeetingType::class, 'meeting_type_id' );
	}

	/**
	 * Get the booking type.
	 *
	 * @since 1.2.0
	 *
	 * @return string
	 */
	public function booking_type() {
		return $this->attributes['booking_type'] ?? 'service_booking';
	}

	/**
	 * Get the meeting type ID.
	 *
	 * @since 1.2.0
	 *
	 * @return int|null
	 */
	public function meeting_type_id() {
		return $this->attributes['meeting_type_id'] ?? null;
	}

	/**
	 * Get the event ID.
	 *
	 * @since 1.2.0
	 *
	 * @return int|null
	 */
	public function event_id() {
		return $this->attributes['event_id'] ?? null;
	}

	/**
	 * Get all customer bookings for this appointment.
	 *
	 * @since 1.0.0
	 */
	public function get_booking() {
		return $this->hasMany( CustomerBooking::class, 'appointment_id', 'id' );
	}

	/**
	 * Retrieve the associated payment ID for this appointment.
	 *
	 * This method looks up the payment record linked to the current appointment
	 * through the `CustomerBooking` model and the `radius_booking_payments` table.
	 * If a payment exists, it returns the corresponding payment ID; otherwise, it returns null.
	 *
	 * @since 1.0.0
	 *
	 * @return int|null The associated payment ID if found, or null if no payment exists.
	 */
	public function get_payment_id() {
		$payment = CustomerBooking::where( 'appointment_id', $this->get_id() )->leftJoin( 'radius_booking_payments', 'radius_booking_payments.booking_id', '=', 'radius_booking_customer_bookings.id' )->first();
		if ( ! $payment ) {
			return null;
		}
		$paymentObj = Payment::find( $payment->id );
		if ( $paymentObj ) {
			return $paymentObj->get_id();
		}
		return null;
	}

	/**
	 * Get the total number of appointments.
	 *
	 * Executes a database query to count all appointment records
	 * associated with this model.
	 *
	 * @since 1.0.0
	 *
	 * @return int The total count of appointment records.
	 */
	public static function totalAppointment() {
		return static::query()->count();
	}

	/**
	 * Get the current status of the model.
	 *
	 * Retrieves the value of the `status` attribute from the model's attributes array.
	 *
	 * @since 1.0.0
	 *
	 * @return string|null The current status value, or null if not set.
	 */
	public function get_status() {
		return $this->attributes['status'];
	}

	public function get_service() {
		return $this->belongsTo( Service::class );
	}

	public function get_employee_id(  ) {
		return $this->attributes['employee_id'];
	}
}
