<?php

/**
 * @property string $full_name
 */
class OsAgentModel extends OsModel {
	public $id,
		$first_name         = '',
		$last_name          = '',
		$display_name,
		$email,
		$phone,
		$password,
		$avatar_image_id,
		$bio_image_id,
		$is_custom_price    = false,
		$is_custom_hours    = false,
		$is_custom_duration = false,
		$custom_hours,
		$wp_user_id,
		$title,
		$bio,
		$features,
		$extra_emails,
		$extra_phones,
		$status,
		$meta_class         = 'OsAgentMetaModel',
		$updated_at,
		$created_at,
		$services_agents_table_name;

	function __construct( $id = false ) {
		parent::__construct();
		$this->table_name                 = LATEPOINT_TABLE_AGENTS;
		$this->services_agents_table_name = LATEPOINT_TABLE_AGENTS_SERVICES;
		$this->nice_names                 = array(
			'first_name' => __( 'First Name', 'latepoint' ),
			'password'   => __( 'Password', 'latepoint' ),
			'email'      => __( 'Email Address', 'latepoint' ),
			'wp_user_id' => __( 'Connected WordPress User', 'latepoint' ),
			'last_name'  => __( 'Last Name', 'latepoint' ),
		);

		if ( $id ) {
			$this->load_by_id( $id );
		}
	}


	public function get_initials() {
		return mb_substr( $this->first_name, 0, 1 ) . mb_substr( $this->last_name, 0, 1 );
	}

	public function get_edit_link() {
		return OsRouterHelper::build_link( [ 'agents', 'edit_form' ], [ 'id' => $this->id ] );
	}

	public function generate_data_vars(): array {
		return [
			'id'        => $this->id,
			'full_name' => $this->full_name,
			'email'     => $this->email,
			'phone'     => $this->phone,
		];
	}

	protected function params_to_save( $role = 'admin' ) {
		$params_to_save = array(
			'id',
			'first_name',
			'last_name',
			'display_name',
			'email',
			'phone',
			'password',
			'wp_user_id',
			'bio_image_id',
			'title',
			'bio',
			'features',
			'status',
			'extra_emails',
			'extra_phones',
			'avatar_image_id',
			'custom_hours',
		);
		return $params_to_save;
	}

	protected function allowed_params( $role = 'admin' ) {
		$allowed_params = array(
			'id',
			'first_name',
			'last_name',
			'display_name',
			'email',
			'phone',
			'password',
			'wp_user_id',
			'bio_image_id',
			'title',
			'bio',
			'features',
			'extra_emails',
			'extra_phones',
			'status',
			'avatar_image_id',
			'custom_hours',
		);
		return $allowed_params;
	}


	protected function properties_to_validate() {
		$validations = array(
			'email'      => array( 'presence' ),
			'wp_user_id' => array( 'uniqueness' ),
		);
		return $validations;
	}


	public function count_number_of_connected_locations( $service_id = false ) {
		if ( $this->is_new_record() ) {
			return 0;
		}
		$args = [ 'agent_id' => $this->id ];
		if ( $service_id ) {
			$args['service_id'] = $service_id;
		}
		return OsConnectorHelper::count_connections( $args, 'location_id' );
	}

	public function delete_meta_by_key( $meta_key ) {
		if ( $this->is_new_record() ) {
			return false;
		}

		$meta = new OsAgentMetaModel();
		return $meta->delete_by_key( $meta_key, $this->id );
	}

	public function get_meta_by_key( $meta_key, $default = false ) {
		if ( $this->is_new_record() ) {
			return $default;
		}

		$meta = new OsAgentMetaModel();
		return $meta->get_by_key( $meta_key, $this->id, $default );
	}

	public function save_meta_by_key( $meta_key, $meta_value ) {
		if ( $this->is_new_record() ) {
			return false;
		}

		$meta = new OsAgentMetaModel();
		return $meta->save_by_key( $meta_key, $meta_value, $this->id );
	}

	protected function set_defaults() {
		if ( empty( $this->status ) ) {
			$this->status = LATEPOINT_AGENT_STATUS_ACTIVE;
		}
	}

	public function has_location( $location_id ) {
		return OsConnectorHelper::has_connection(
			[
				'agent_id'    => $this->id,
				'location_id' => $location_id,
			] 
		);
	}


	protected function get_total_future_bookings() {
		$bookings = new OsBookingModel();
		$total    = $bookings->where( [ 'agent_id' => $this->id ] )->should_be_in_future()->count();
		return $total;
	}

	protected function get_total_synced_future_bookings() {
		$bookings = new OsBookingModel();
		$total    = $bookings->where(
			[
				'agent_id'                                 => $this->id,
				LATEPOINT_TABLE_BOOKING_META . '.meta_key' => 'google_calendar_event_id',
			] 
		)
			->join( LATEPOINT_TABLE_BOOKING_META, [ 'object_id' => LATEPOINT_TABLE_BOOKINGS . '.id' ] )
			->should_be_in_future()
			->count();
		return $total;
	}

	protected function get_future_bookings( $limit = false ) {
		$bookings = new OsBookingModel();
		if ( $limit ) {
			$bookings = $bookings->set_limit( $limit );
		}
		return $bookings->order_by( 'start_date, start_time asc' )->where( [ 'agent_id' => $this->id ] )->should_be_in_future()->get_results_as_models();
	}

	public function should_be_active() {
		return $this->where( [ 'status !=' => LATEPOINT_AGENT_STATUS_DISABLED ] );
	}

	public function has_service_and_location( $service_id, $location_id ) {
		if ( $this->is_new_record() ) {
			return false;
		}
		return OsConnectorHelper::has_connection(
			[
				'location_id' => $location_id,
				'agent_id'    => $this->id,
				'service_id'  => $service_id,
			] 
		);
	}

	public function get_features_arr() {
		$features_arr = [];
		if ( ! empty( $this->features ) ) {
			$features = json_decode( $this->features, true );
			if ( ! empty( $features ) ) {
				foreach ( $features as $feature ) {
					if ( $feature['value'] && $feature['label'] ) {
						$features_arr[] = $feature;
					}
				}
			}
		}
		return $features_arr;
	}

	public function save_custom_schedule( $work_periods, int $location_id = 0 ) {
		foreach ( $work_periods as &$work_period ) {
			$work_period['agent_id']    = $this->id;
			$work_period['location_id'] = $location_id;
		}
		unset( $work_period );
		OsWorkPeriodsHelper::save_work_periods( $work_periods );
	}

	public function delete_custom_schedule( int $location_id = 0 ) {
		$work_periods_model = new OsWorkPeriodModel();
		$work_periods       = $work_periods_model->where(
			array(
				'agent_id'    => $this->id,
				'service_id'  => 0,
				'location_id' => $location_id,
				'custom_date' => 'IS NULL',
			)
		)->get_results_as_models();
		if ( is_array( $work_periods ) ) {
			foreach ( $work_periods as $work_period ) {
				$work_period->delete();
			}
		}
	}

	public function has_service( $service_id ) {
		foreach ( $this->services as $service ) {
			if ( $service->id == $service_id ) {
				return true;
			}
		}
		return false;
	}


	public function save_services() {
		foreach ( $this->services as $service ) {
			$service_connection_row = $this->db->get_row( $this->db->prepare( 'SELECT id FROM ' . $this->services_agents_table_name . ' WHERE agent_id = %d AND service_id = %d', array( $this->id, $service->id ) ) );
			if ( $service_connection_row ) {
				$update_data = array(
					'is_custom_hours'    => $service->is_custom_hours,
					'is_custom_price'    => $service->is_custom_price,
					'is_custom_duration' => $service->is_custom_duration,
				);
				$this->db->update( $this->services_agents_table_name, $update_data, array( 'id' => $service_connection_row->id ) );
			} else {
				$insert_data = array(
					'service_id'         => $service->id,
					'agent_id'           => $this->id,
					'is_custom_hours'    => $service->is_custom_hours,
					'is_custom_price'    => $service->is_custom_price,
					'is_custom_duration' => $service->is_custom_duration,
				);
				if ( $this->db->insert( $this->services_agents_table_name, $insert_data ) ) {
					$service_connection_row_id = $this->db->insert_id;
				}
			}
		}
		return true;
	}


	public function remove_services_by_ids( $ids_to_remove = array() ) {
		if ( $ids_to_remove ) {
			$query = $this->db->prepare( 'DELETE FROM %i WHERE agent_id = %d AND service_id IN ' . OsModel::where_in_array_to_string( $ids_to_remove ), [ $this->services_agents_table_name, $this->id ] );
			$this->db->query( $query );
		}
	}


	public function get_service_ids_to_remove( $new_services = array() ) {
		$current_service_ids = $this->get_current_service_ids_from_db();
		$new_service_ids     = array();
		foreach ( $new_services as $service ) {
			if ( $service['connected'] == 'yes' ) {
				$new_service_ids[] = $service['id'];
			}
		}
		$service_ids_to_remove = array_diff( $current_service_ids, $new_service_ids );
		return $service_ids_to_remove;
	}


	public function save_locations_and_services( $services ) {
		if ( ! $services ) {
			return true;
		}
		$connections_to_save   = [];
		$connections_to_remove = [];
		foreach ( $services as $service_key => $locations ) {
			$service_id = str_replace( 'service_', '', $service_key );
			foreach ( $locations as $location_key => $location ) {
				$location_id = str_replace( 'location_', '', $location_key );
				$connection  = [
					'service_id'  => $service_id,
					'agent_id'    => $this->id,
					'location_id' => $location_id,
				];
				if ( $location['connected'] == 'yes' ) {
					$connections_to_save[] = $connection;
				} else {
					$connections_to_remove[] = $connection;
				}
			}
		}
		if ( ! empty( $connections_to_save ) ) {
			foreach ( $connections_to_save as $connection_to_save ) {
				OsConnectorHelper::save_connection( $connection_to_save );
			}
		}
		if ( ! empty( $connections_to_remove ) ) {
			foreach ( $connections_to_remove as $connection_to_remove ) {
				OsConnectorHelper::remove_connection( $connection_to_remove );
			}
			// Clean up location-specific schedules for fully disconnected locations
			$cleaned_location_ids = [];
			foreach ( $connections_to_remove as $conn ) {
				$loc_id = (int) $conn['location_id'];
				if ( $loc_id > 0 && ! in_array( $loc_id, $cleaned_location_ids ) ) {
					if ( ! $this->has_location( $loc_id ) ) {
						$this->delete_custom_schedule( $loc_id );
						$wp_model = new OsWorkPeriodModel();
						$wp_model->delete_where(
							[
								'agent_id'    => $this->id,
								'location_id' => $loc_id,
							] 
						);
						$cleaned_location_ids[] = $loc_id;
					}
				}
			}
		}
		return true;
	}

	public function set_features( $features ) {
		$this->features = wp_json_encode( $features );
	}

	public function get_current_service_ids_from_db() {
		$query        = $this->db->prepare( 'SELECT service_id FROM ' . $this->services_agents_table_name . ' WHERE agent_id = %d', $this->id );
		$service_rows = $this->db->get_results( $query );

		$service_ids = array();

		if ( $service_rows ) {
			foreach ( $service_rows as $service_row ) {
				$service_ids[] = $service_row->service_id;
			}
		}
		return $service_ids;
	}


	public function get_current_service_ids() {
		$service_ids = array();
		foreach ( $this->services as $service ) {
			$service_ids[] = $service->id;
		}
		return $service_ids;
	}

	public function set_services( $service_datas ) {
		$this->services = array();

		foreach ( $service_datas as $service_data ) {
			if ( $service_data['connected'] == 'yes' ) {
				$service                     = new OsserviceModel();
				$service->id                 = $service_data['id'];
				$service->is_custom_hours    = $service_data['is_custom_hours'];
				$service->is_custom_price    = $service_data['is_custom_price'];
				$service->is_custom_duration = $service_data['is_custom_duration'];
				$this->services[]            = $service;
			}
		}
		return $this;
	}

	public function filter_allowed_records(): OsModel {
		if ( ! OsRolesHelper::are_all_records_allowed( 'agent' ) ) {
			$this->filter_where_conditions( [ 'id' => OsRolesHelper::get_allowed_records( 'agent' ) ] );
		}
		return $this;
	}

	public function get_services() {
		if ( ! isset( $this->services ) ) {
			$query         = 'SELECT * FROM ' . $this->services_agents_table_name . ' WHERE agent_id = %d GROUP BY service_id';
			$query_args    = array( $this->id );
			$services_rows = $this->get_query_results( $query, $query_args );

			$this->services = array();

			if ( $services_rows ) {
				foreach ( $services_rows as $service_row ) {
					$service                     = new OsServiceModel( $service_row->service_id );
					$service->is_custom_hours    = $service_row->is_custom_hours;
					$service->is_custom_price    = $service_row->is_custom_price;
					$service->is_custom_duration = $service_row->is_custom_duration;
					$this->services[]            = $service;
				}
			}
		}
		return $this->services;
	}


	protected function before_create() {
		if ( empty( $this->password ) ) {
			$this->password = wp_hash_password( bin2hex( openssl_random_pseudo_bytes( 8 ) ) );
		}
	}

	protected function before_save() {
	}

	public function get_full_name() {
		$full_name = trim( join( ' ', array( $this->first_name, $this->last_name ) ) );
		return empty( $full_name ) ? __( 'Agent', 'latepoint' ) : $full_name;
	}

	protected function get_name_for_front() {
		if ( isset( $this->display_name ) && ! empty( $this->display_name ) ) {
			return $this->display_name;
		} else {
			return $this->get_full_name();
		}
	}

	public function get_avatar_url() {
		return OsAgentHelper::get_avatar_url( $this );
	}

	public function get_avatar_image() {
		return '<img src="' . $this->get_avatar_url() . '"/>';
	}

	public function get_bio_image_url() {
		return OsAgentHelper::get_bio_image_url( $this );
	}

	public function get_bio_image() {
		return '<img src="' . $this->get_bio_image_url() . '"/>';
	}


	public function delete( $id = false ) {
		if ( ! $id && isset( $this->id ) ) {
			$id = $this->id;
		}
		if ( $id && $this->db->delete( $this->table_name, array( 'id' => $id ), array( '%d' ) ) ) {
			$this->db->delete( LATEPOINT_TABLE_AGENTS_SERVICES, array( 'agent_id' => $id ), array( '%d' ) );
			$this->db->delete( LATEPOINT_TABLE_WORK_PERIODS, array( 'agent_id' => $id ), array( '%d' ) );
			$this->db->delete( LATEPOINT_TABLE_AGENT_META, array( 'object_id' => $id ), array( '%d' ) );
			return true;
		} else {
			return false;
		}
	}
}
