<?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\Models;

use RadiusTheme\RadiusBooking\Abstracts\BaseModel;

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

/**
 * Class Service
 *
 * Represents a service offered in the booking system.
 *
 * @package RadiusTheme\RadiusBooking\Models
 *
 * @property int $id
 * @property string $name
 * @property string|null $description
 * @property int $duration  Duration in minutes
 * @property float $price
 */
class Service extends BaseModel {

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

	/**
	 * The attributes that are mass assignable.
	 *
	 * @var array
	 */
	protected array $fillable = array(
		'name',
		'description',
		'color',
		'price',
		'status',
		'category_id',
		'min_capacity',
		'max_capacity',
		'duration',
		'time_before',
		'time_after',
		'bringing_anyone',
		'priority',
		'picture_full_path',
		'picture_thumb_path',
		'position',
		'is_visible',
		'aggregated_price',
		'settings',
		'recurring_cycle',
		'recurring_sub',
		'recurring_payment',
		'deposit_payment',
		'deposit_type',
		'deposit_per_person',
		'deposit',
		'full_payment',
		'mandatory_extra',
		'min_selected_extras',
		'custom_pricing',
		'max_extra_people',
		'limit_per_customer',
		'translations',
		'listing_id',
		'source_type',
	);

	/**
	 * The attributes that should be cast to native types.
	 *
	 * @var array
	 */
	protected array $casts = array(
		'price'               => 'float',
		'duration'            => 'integer',
		'category_id'         => 'integer',
		'min_capacity'        => 'integer',
		'max_capacity'        => 'integer',
		'time_before'         => 'integer',
		'time_after'          => 'integer',
		'bringing_anyone'     => 'boolean',
		'position'            => 'integer',
		'is_visible'          => 'boolean',
		'aggregated_price'    => 'boolean',
		'settings'            => 'json',
		'recurring_payment'   => 'integer',
		'deposit_payment'     => 'boolean',
		'deposit_per_person'  => 'boolean',
		'deposit'             => 'float',
		'full_payment'        => 'boolean',
		'mandatory_extra'     => 'boolean',
		'min_selected_extras' => 'integer',
		'max_extra_people'    => 'integer',
		'limit_per_customer'  => 'json',
		'translations'        => 'json',
		'listing_id'          => 'integer',
	);

	/**
	 * Get all appointments associated with the service.
	 *
	 * @return \RadiusTheme\RadiusBooking\Core\ORM\Relations\HasMany
	 */
	public function appointments() {
		return $this->hasMany( Appointment::class );
	}

	/**
	 * Defines a relationship where this model belongs to a category.
	 *
	 * @return \RadiusTheme\RadiusBooking\Core\ORM\Relations\BelongsTo
	 */
	public function category() {
		return $this->belongsTo( Category::class, 'category_id' );
	}

	/**
	 * Defines a relationship where this model has many assigned employee services.
	 *
	 * @return \RadiusTheme\RadiusBooking\Core\ORM\Relations\HasMany
	 */
	public function getAssignService() {
		return $this->hasMany( EmployeeService::class, 'service_id', 'id' );
	}

	/**
	 * Retrieves the price from the attributes array.
	 *
	 * @return mixed Returns the value of the 'price' attribute.
	 */
	public function get_price() {
		return $this->attributes['price'];
	}

	/**
	 * Retrieves the duration from the attributes array.
	 *
	 * @return mixed Returns the value of the 'duration' attribute.
	 */
	public function get_duration() {
		return $this->attributes['duration'];
	}

	/**
	 * Retrieves the name from the attributes array.
	 *
	 * @return mixed Returns the value of the 'name' attribute.
	 */
	public function get_name() {
		return $this->attributes['name'];
	}

	/**
	 * Retrieves the ID from the attributes array.
	 *
	 * @return mixed Returns the value of the 'id' attribute.
	 */
	public function get_id() {
		return $this->attributes['id'];
	}

	/**
	 * Retrieves the maximum capacity from the attributes array.
	 *
	 * @return mixed The value of the 'max_capacity' attribute.
	 */
	public function max_capacity() {
		return $this->attributes['max_capacity'];
	}

	/**
	 * Retrieves the minimum capacity from the attributes array.
	 *
	 * @return mixed The value of the 'min_capacity' attribute.
	 */
	public function min_capacity() {
		return $this->attributes['min_capacity'];
	}

	/**
	 * Retrieves the buffer time after an event from the attributes array.
	 *
	 * @return mixed The value of the 'time_after' attribute.
	 */
	public function get_buffer_after() {
		return $this->attributes['time_after'];
	}

	/**
	 * Retrieves the value of the 'time_before' attribute from the attributes array.
	 *
	 * @return mixed The value associated with the 'time_before' key in the attributes array.
	 */
	public function get_buffer_before() {
		return $this->attributes['time_before'];
	}

	/**
	 * Retrieves the 'settings' attribute from the attributes array after attempting to unserialize it.
	 *
	 * @return mixed The value of the 'settings' attribute, possibly unserialized.
	 */
	public function get_settings() {
		return maybe_unserialize( $this->attributes['settings'] );
	}

	/**
	 * Retrieves the general settings from the settings array.
	 *
	 * @return array The general settings if available, otherwise an empty array.
	 */
	public function get_general_setting() {
		$settings = $this->get_settings();

		return $settings['general'] ?? array();
	}

	/**
	 * Retrieves the payment methods from the settings array.
	 *
	 * @return array The array of payment methods if available, otherwise an empty array.
	 */
	public function get_payment_method() {
		$settings = $this->get_settings();

		return $settings['paymentMethods'] ?? array();
	}

	/**
	 * Retrieves the integrations from the settings.
	 *
	 * @return array The integrations array from the settings, or an empty array if not set.
	 */
	public function integrations() {
		$settings = $this->get_settings();

		return $settings['integrations'] ?? array();
	}

	/**
	 * Retrieves the default appointment status.
	 * Priority: Per-service (Pro) > Global statuses setting.
	 */
	public function get_appointment_status() {
		// Fallback: global setting.
		$global         = \RadiusTheme\RadiusBooking\Helpers\SettingsHelper::get_setting( 'statuses' );
		$default_status = $global['default'] ?? 'confirmed';

		return apply_filters( 'rtrb_service_appointment_status', $default_status, $this );
	}

	/**
	 * Retrieves the minimum booking time.
	 * Priority: Per-service (Pro) > Global restrictions.earliest.
	 */
	public function get_min_booking_time() {
		// Fallback: global setting.
		$global  = \RadiusTheme\RadiusBooking\Helpers\SettingsHelper::get_setting( 'restrictions' );
		$default = self::parse_relative_time_to_seconds( $global['earliest'] ?? '' );

		return apply_filters( 'rtrb_service_min_booking_time', $default, $this );
	}

	/**
	 * Retrieves the minimum cancel time.
	 * Priority: Per-service (Pro) > Global restrictions.minCancelTime.
	 */
	public function get_min_cancel_time() {
		// Fallback: global setting.
		$global  = \RadiusTheme\RadiusBooking\Helpers\SettingsHelper::get_setting( 'restrictions' );
		$default = self::parse_relative_time_to_seconds( $global['minCancelTime'] ?? '' );

		return apply_filters( 'rtrb_service_min_cancel_time', $default, $this );
	}

	/**
	 * Retrieves the minimum reschedule time.
	 * Priority: Per-service (Pro) > Global restrictions.minRescheduleTime.
	 */
	public function get_min_reschedule_time() {
		// Fallback: global setting.
		$global  = \RadiusTheme\RadiusBooking\Helpers\SettingsHelper::get_setting( 'restrictions' );
		$default = self::parse_relative_time_to_seconds( $global['minRescheduleTime'] ?? '' );

		return apply_filters( 'rtrb_service_min_reschedule_time', $default, $this );
	}

	/**
	 * Retrieves the booking advance period in days.
	 * Priority: Per-service (Pro) > Global restrictions.latest.
	 */
	public function get_booking_advance_period() {
		// Fallback: global setting.
		$global  = \RadiusTheme\RadiusBooking\Helpers\SettingsHelper::get_setting( 'restrictions' );
		$latest  = $global['latest'] ?? '+6 months';
		$seconds = self::parse_relative_time_to_seconds( $latest );

		if ( 'disabled' === $seconds || 0 === (int) $seconds ) {
			$default = 365;
		} else {
			$default = max( 1, (int) round( (int) $seconds / 86400 ) );
		}

		return apply_filters( 'rtrb_service_booking_advance_period', $default, $this );
	}

	/**
	 * Converts a relative time string (e.g. "+24 hours", "+2 days") to seconds.
	 *
	 * @param string $time_string Relative time like "+1 hour", "+30 minutes", "+2 days", "+6 months".
	 *
	 * @return string|int Seconds as a string for compatibility, or 'disabled' if empty/invalid.
	 */
	private static function parse_relative_time_to_seconds( $time_string ) {
		if ( empty( $time_string ) ) {
			return 'disabled';
		}

		$time_string = trim( $time_string );

		// Already a numeric value (seconds).
		if ( is_numeric( $time_string ) ) {
			return $time_string;
		}

		try {
			$now    = new \DateTime( 'now', wp_timezone() );
			$future = clone $now;
			$future->modify( $time_string );
			$diff = $future->getTimestamp() - $now->getTimestamp();

			return $diff > 0 ? (string) $diff : 'disabled';
		} catch ( \Exception $e ) {
			return 'disabled';
		}
	}

	/**
	 * Retrieves the recurring cycle from the attributes array.
	 *
	 * @return mixed
	 */
	public function recurring_cycle() {
		return $this->attributes['recurring_cycle'];
	}

	/**
	 * Retrieves the value of the 'recurring_sub' attribute.
	 *
	 * @return mixed The value of the 'recurring_sub' attribute.
	 */
	public function recurring_sub() {
		return $this->attributes['recurring_sub'];
	}

	/**
	 * Retrieves the recurring payment attribute.
	 *
	 * @return mixed The value of the recurring payment attribute.
	 */
	public function recurring_payment() {
		return $this->attributes['recurring_payment'];
	}

	/**
	 * Check if this service is sourced from a Classified Listing.
	 *
	 * @return bool
	 */
	public function isFromClassifiedListing() {
		return ( $this->attributes['source_type'] ?? 'manual' ) === 'classified_listing';
	}

	/**
	 * Get the Classified Listing permalink if linked.
	 *
	 * @return string|null
	 */
	public function getListingUrl() {
		$listing_id = $this->attributes['listing_id'] ?? null;
		if ( $listing_id ) {
			return get_permalink( $listing_id );
		}
		return null;
	}
}
