<?php 

class OsConnectorHelper {


	/**
	 *
	 * Returns an array of all the possible connections/resources combinations(between agent/service/location) available to satisfy a booking request
	 *
	 * @param \LatePoint\Misc\BookingRequest $booking_request
	 * @return OsConnectorModel[]
	 */
	public static function get_connections_that_satisfy_booking_request( \LatePoint\Misc\BookingRequest $booking_request, $filter_based_on_access = false ): array {
		$connection_model = new OsConnectorModel();

		// agent
		if ( $filter_based_on_access && ! OsRolesHelper::are_all_records_allowed( 'agent' ) ) {
			$allowed_ids = OsRolesHelper::get_allowed_records( 'agent' );
			// if nothing is allowed, or the requested ID is not part of allowed - return blank
			if ( empty( $allowed_ids ) || ( $allowed_ids != LATEPOINT_ALL && ( is_array( $booking_request->agent_id ) && ! empty( reset( $booking_request->agent_id ) ) && ! array_intersect( $booking_request->agent_id, $allowed_ids ) ) ) ) {
				return [];
			}
			if ( $booking_request->agent_id ) {
				$connection_model->where( [ 'agent_id' => $booking_request->agent_id ] );
			} else {
				// agent_id is 0, it means ANY is requested, filter based on what's allowed
				$connection_model->where( [ 'agent_id' => $allowed_ids ] );
			}
		} else {
			$active_agents    = new OsAgentModel();
			$active_agent_ids = array_column( $active_agents->select( 'id' )->should_be_active()->get_results( ARRAY_A ), 'id' );

			if ( empty( $active_agent_ids ) ) {
				return []; // no active agents
			}

			if ( empty( $booking_request->agent_id ) ) {
				// any agent requested, search in a list of active
				$connection_model->where( [ 'agent_id' => $active_agent_ids ] );
			} else {
				// specific agent/or agents requested, check if it's in a list of active agents
				if ( is_array( $booking_request->agent_id ) ) {
					// array of agents requested, intersect
					if ( array_intersect( $booking_request->agent_id, $active_agent_ids ) ) {
						$connection_model->where( [ 'agent_id' => array_intersect( $booking_request->agent_id, $active_agent_ids ) ] );
					} else {
						return [];
					}
				} else {
					if ( in_array( $booking_request->agent_id, $active_agent_ids ) ) {
						$connection_model->where( [ 'agent_id' => $booking_request->agent_id ] );
					} else {
						// requested agent not in a list of active agents
						return [];
					}
				}
			}
		}

		// location
		if ( $filter_based_on_access && ! OsRolesHelper::are_all_records_allowed( 'location' ) ) {
			$allowed_ids = OsRolesHelper::get_allowed_records( 'location' );
			// if nothing is allowed, or the requested ID is not part of allowed - return blank
			if ( empty( $allowed_ids ) || ( $allowed_ids != LATEPOINT_ALL && ( is_array( $booking_request->location_id ) && ! empty( reset( $booking_request->location_id ) ) && ! array_intersect( $booking_request->location_id, $allowed_ids ) ) ) ) {
				return [];
			}
			if ( $booking_request->location_id ) {
				$connection_model->where( [ 'location_id' => $booking_request->location_id ] );
			} else {
				// location_id is 0, it means ANY is requested, filter based on what's allowed
				$connection_model->where( [ 'location_id' => $allowed_ids ] );
			}
		} else {
			$active_locations    = new OsLocationModel();
			$active_location_ids = array_column( $active_locations->select( 'id' )->should_be_active()->get_results( ARRAY_A ), 'id' );


			if ( empty( $active_location_ids ) ) {
				return []; // no active locations
			}

			if ( empty( $booking_request->location_id ) ) {
				// any location requested, search in a list of active
				$connection_model->where( [ 'location_id' => $active_location_ids ] );
			} else {
				// specific location/or locations requested, check if it's in a list of active locations
				if ( is_array( $booking_request->location_id ) ) {
					// array of locations requested, intersect
					if ( array_intersect( $booking_request->location_id, $active_location_ids ) ) {
						$connection_model->where( [ 'location_id' => array_intersect( $booking_request->location_id, $active_location_ids ) ] );
					} else {
						return [];
					}
				} else {
					if ( in_array( $booking_request->location_id, $active_location_ids ) ) {
						$connection_model->where( [ 'location_id' => $booking_request->location_id ] );
					} else {
						// requested location not in a list of active locations
						return [];
					}
				}
			}
		}

		// service
		if ( $filter_based_on_access && ! OsRolesHelper::are_all_records_allowed( 'service' ) ) {
			$allowed_ids = OsRolesHelper::get_allowed_records( 'service' );
			// if nothing is allowed, or the requested ID is not part of allowed - return blank
			if ( empty( $allowed_ids ) || ( $allowed_ids != LATEPOINT_ALL && ( is_array( $booking_request->service_id ) && ! empty( reset( $booking_request->service_id ) ) && ! array_intersect( $booking_request->service_id, $allowed_ids ) ) ) ) {
				return [];
			}
			if ( $booking_request->service_id ) {
				$connection_model->where( [ 'service_id' => $booking_request->service_id ] );
			} else {
				// service_id is 0, it means ANY is requested, filter based on what's allowed
				$connection_model->where( [ 'service_id' => $allowed_ids ] );
			}
		} else {
			$active_services    = new OsServiceModel();
			$active_service_ids = array_column( $active_services->select( 'id' )->should_be_active()->get_results( ARRAY_A ), 'id' );

			if ( empty( $active_service_ids ) ) {
				return []; // no active services
			}

			if ( empty( $booking_request->service_id ) ) {
				// any service requested, search in a list of active
				$connection_model->where( [ 'service_id' => $active_service_ids ] );
			} else {
				// specific service/or services requested, check if it's in a list of active services
				if ( is_array( $booking_request->service_id ) ) {
					// array of services requested, intersect
					if ( array_intersect( $booking_request->service_id, $active_service_ids ) ) {
						$connection_model->where( [ 'service_id' => array_intersect( $booking_request->service_id, $active_service_ids ) ] );
					} else {
						return [];
					}
				} else {
					if ( in_array( $booking_request->service_id, $active_service_ids ) ) {
						$connection_model->where( [ 'service_id' => $booking_request->service_id ] );
					} else {
						// requested service not in a list of active services
						return [];
					}
				}
			}
		}

		return $connection_model->get_results_as_models();
	}

	// expects [agent_id, 'service_id', 'location_id']
	public static function count_connections( $connection_query_arr, $group_by = false ) {
		$connection_model = new OsConnectorModel();
		$connection_model->where( $connection_query_arr );
		if ( $group_by ) {
			$results = $connection_model->select( $group_by )->group_by( $group_by )->get_results();
			$total   = count( $results );
		} else {
			$total = $connection_model->count();
		}
		return $total;
	}

	public static function can_satisfy_booking_request( \LatePoint\Misc\BookingRequest $booking_request ) {
		$connection_model = new OsConnectorModel();
		return $connection_model->where(
			[
				'agent_id'    => $booking_request->agent_id,
				'location_id' => $booking_request->location_id,
				'service_id'  => $booking_request->service_id,
			] 
		)->set_limit( 1 )->get_results_as_models();
	}

	public static function has_connection( $connection_arr ) {
		$connection_model = new OsConnectorModel();
		return $connection_model->where( $connection_arr )->set_limit( 1 )->get_results_as_models();
	}

	// expects [agent_id, 'service_id', 'location_id']
	public static function save_connection( $connection_arr ) {
		$connection_model    = new OsConnectorModel();
		$existing_connection = $connection_model->where( $connection_arr )->set_limit( 1 )->get_results_as_models();
		if ( $existing_connection ) {
			// Update
		} else {
			// Insert
			$connection_model->set_data( $connection_arr );
			return $connection_model->save();
		}
	}


	// object type: agent_id, service_id, location_id
	public static function get_connected_object_ids( $object_type = 'agent_id', $connections = [] ) {
		if ( ! in_array( $object_type, [ 'agent_id', 'service_id', 'location_id' ] ) ) {
			return false;
		}
		$clean_connections = [];
		if ( isset( $connections['agent_id'] ) && ! empty( $connections['agent_id'] ) && $connections['agent_id'] != LATEPOINT_ANY_AGENT ) {
			$clean_connections['agent_id'] = $connections['agent_id'];
		}
		if ( isset( $connections['service_id'] ) && ! empty( $connections['service_id'] ) ) {
			$clean_connections['service_id'] = $connections['service_id'];
		}
		if ( isset( $connections['location_id'] ) && ! empty( $connections['location_id'] ) && $connections['location_id'] != LATEPOINT_ANY_LOCATION ) {
			$clean_connections['location_id'] = $connections['location_id'];
		}
		$connection_model = new OsConnectorModel();
		if ( ! empty( $clean_connections ) ) {
			$connection_model->where( $clean_connections );
		}
		$objects = $connection_model->select( $object_type )->group_by( $object_type )->get_results();
		$ids     = [];
		if ( $objects ) {
			foreach ( $objects as $object ) {
				if ( isset( $object->$object_type ) ) {
					$ids[] = $object->$object_type;
				}
			}
		}
		return $ids;
	}


	// expects [agent_id, 'service_id', 'location_id']
	public static function remove_connection( $connection_arr ) {
		$connection_model = new OsConnectorModel();
		if ( isset( $connection_arr['agent_id'] ) && isset( $connection_arr['service_id'] ) && isset( $connection_arr['location_id'] ) ) {
			$existing_connection = $connection_model->where( $connection_arr )->set_limit( 1 )->get_results_as_models();
			if ( $existing_connection ) {
				$existing_connection->delete();
			}
		}
	}
}
