<?php

namespace SugarCalendarBookings\Services;

use SugarCalendarBookings\Appointments\AppointmentModel;
use SugarCalendarBookings\Availability\WorkingScheduleDefaults;
use SugarCalendarBookings\Employees\EmployeeModel;
use SugarCalendarBookings\Locations\LocationModel;
use SugarCalendarBookings\Notifications\Emails\EmailDefaults;
use SugarCalendarBookings\Support\Database\AbstractModel;
use SugarCalendarBookings\Support\Database\Relations\BelongsToManyRelation;
use SugarCalendarBookings\Support\Database\Relations\HasManyRelation;
use SugarCalendarBookings\Support\Tags\TagModel;

/**
 * Service model.
 *
 * @since 1.0.0
 * @since 1.5.0 Added the $slug property.
 *
 * @property int                     $id
 * @property string                  $name
 * @property string                  $slug
 * @property string                  $status
 * @property string                  $description
 * @property int                     $duration
 * @property float                   $price
 * @property string                  $color
 * @property int                     $author_id
 * @property string                  $created_at
 * @property string                  $updated_at
 * @property int                     $feature_image_id
 * @property bool                    $use_default_working_schedule
 * @property array                   $working_schedule
 * @property string                  $prev_status
 * @property array                   $online_locations
 * @property bool                    $override_payment_methods
 * @property array<string>           $payment_gateways
 * @property bool                    $override_email_notifications
 * @property array                   $emails
 * @property array<LocationModel>    $locations
 * @property array<TagModel>         $tags
 * @property array<AppointmentModel> $appointments
 */
class ServiceModel extends AbstractModel {

	/**
	 * The database table name without prefix.
	 *
	 * This should be set in the subclass.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	protected static $table_name = 'services';

	/**
	 * The model type identifier.
	 *
	 * This should be set in the subclass.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	protected static $type = 'service';

	/**
	 * Column formats for the model.
	 *
	 * @since 1.0.0
	 * @since 1.5.0 Added the $slug column format.
	 *
	 * @var array<string, string>
	 */
	protected static $column_formats = [
		'id'          => '%d',
		'name'        => '%s',
		'slug'        => '%s',
		'status'      => '%s',
		'description' => '%s',
		'duration'    => '%d',
		'price'       => '%f',
		'color'       => '%s',
		'author_id'   => '%d',
		'created_at'  => '%s',
		'updated_at'  => '%s',
	];

	/**
	 * Meta keys for the model.
	 *
	 * @since 1.0.0
	 *
	 * @var array<string, mixed>
	 */
	protected static $meta_keys = [
		'feature_image_id',
		'use_default_working_schedule',
		'working_schedule',
		'prev_status',
		'online_locations',
		'override_payment_methods',
		'payment_gateways',
		'override_email_notifications',
		'emails',
		'_amelia_id',
	];

	/**
	 * The attributes and meta that should be cast.
	 *
	 * @since 1.0.0
	 *
	 * @var array<string, string>
	 */
	protected static $casts = [
		'id'                           => 'integer',
		'duration'                     => 'integer',
		'price'                        => 'float',
		'feature_image_id'             => 'integer',
		'use_default_working_schedule' => 'boolean',
		'working_schedule'             => 'array',
		'online_locations'             => 'array',
		'override_payment_methods'     => 'boolean',
		'payment_gateways'             => 'array',
		'override_email_notifications' => 'boolean',
		'emails'                       => 'array',
		'author_id'                    => 'integer',
		'created_at'                   => 'datetime',
		'updated_at'                   => 'datetime',
	];

	/**
	 * Column defaults for the model.
	 *
	 * @since 1.0.0
	 *
	 * @return array<string, mixed>
	 */
	protected static function column_defaults() {

		return [
			'status' => 'enabled',
		];
	}

	/**
	 * Meta defaults for the model.
	 *
	 * @since 1.0.0
	 *
	 * @return array<string, mixed>
	 */
	protected static function meta_defaults() {

		return [
			'use_default_working_schedule' => true,
			'working_schedule'             => WorkingScheduleDefaults::to_array(),
			'online_locations'             => [],
			'override_payment_methods'     => false,
			'payment_gateways'             => [],
			'override_email_notifications' => false,
			'emails'                       => EmailDefaults::to_array(),
		];
	}

	/**
	 * Get the appointments relationship for the service.
	 *
	 * @since 1.0.0
	 *
	 * @return HasManyRelation
	 */
	public function appointments() {

		return $this->has_many( AppointmentModel::class );
	}

	/**
	 * Get the employees relationship for the service.
	 *
	 * @since 1.0.0
	 *
	 * @return BelongsToManyRelation
	 */
	public function employees() {

		return $this->belongs_to_many( EmployeeModel::class );
	}

	/**
	 * Get the locations relationship for the service.
	 *
	 * @since 1.0.0
	 *
	 * @return BelongsToManyRelation
	 */
	public function locations() {

		return $this->belongs_to_many( LocationModel::class )
			->with_pivot( [ 'location_order' ] );
	}

	/**
	 * Get the tags relationship for the service.
	 *
	 * @since 1.0.0
	 *
	 * @return BelongsToManyRelation
	 */
	public function tags() {

		return $this->belongs_to_many(
			TagModel::class,
			'tag_relationships',
			'object_id',
			'tag_id',
			[
				'object_type' => [
					'value'       => self::get_type(),
					'placeholder' => '%s',
				],
			]
		);
	}

	/**
	 * Save the Service model to the database.
	 *
	 * @since 1.0.0
	 *
	 * @return bool True on success, false on failure.
	 */
	public function save() {

		$changes  = $this->get_changes();
		$is_saved = parent::save();

		if ( $is_saved && isset( $changes['status'] ) && $changes['status'] === 'trash' ) {
			$appointments = $this->appointments;

			foreach ( $appointments as $appointment ) {
				$appointment->status = 'trash';

				$appointment->save();
			}
		}

		return $is_saved;
	}

	/**
	 * Get the status label.
	 *
	 * @since 1.0.0
	 *
	 * @return string
	 */
	public function get_status_label() {

		$label = '';

		switch ( $this->status ) {
			case 'enabled':
				$label = esc_html__( 'Enabled', 'sugar-calendar-bookings-scheduling-appointments-lite' );
				break;

			case 'disabled':
				$label = esc_html__( 'Disabled', 'sugar-calendar-bookings-scheduling-appointments-lite' );
				break;

			case 'trash':
				$label = esc_html__( 'Trashed', 'sugar-calendar-bookings-scheduling-appointments-lite' );
				break;
		}

		return $label;
	}
}
