<?php
/**
 * AbstractModelService.php.
 *
 * @package RewardsWP
 */

namespace Awesomemotive\Rewardswp\Abstracts;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Awesomemotive\Rewardswp\Database\DatabaseHandler;
use DI\Container;
use Exception;

/**
 * Base service for CRUD and listing helpers around models and tables.
 */
abstract class AbstractModelService {
	/**
	 * WordPress database handler.
	 *
	 * @since 1.0.0
	 * @var DatabaseHandler
	 */
	protected DatabaseHandler $db_handler;

	/**
	 * Database table object (varies per entity).
	 *
	 * @since 1.0.0
	 * @var AbstractDatabaseTable
	 */
	protected AbstractDatabaseTable $db_table;

	/**
	 * DI Container.
	 *
	 * @since 1.0.0
	 * @var Container
	 */
	protected Container $container;

	/**
	 * Constructor.
	 *
	 * @param DatabaseHandler       $db_handler Database handler instance.
	 * @param AbstractDatabaseTable $db_table   Table instance for the model.
	 * @param Container             $container  DI container instance.
	 */
	public function __construct(
		DatabaseHandler $db_handler,
		AbstractDatabaseTable $db_table,
		Container $container
	) {
		$this->db_handler = $db_handler;
		$this->db_table   = $db_table;
		$this->container  = $container;
	}

	/**
	 * Retrieve objects based on the given parameters and pagination options.
	 *
	 * @param string $model    The class model to instantiate for each result.
	 * @param array  $where    Filtering conditions.
	 * @param int    $per_page Items per page.
	 * @param int    $page     Page number.
	 * @param string $columns  The columns to return date. Default * (all).
	 *
	 * @return array An array of hydrated objects.
	 */
	protected function get_objects( string $model, array $where = [], int $per_page = 10, int $page = 1, string $columns = '*' ): array {
		if (
			isset( $where['meta_query'] ) &&
			! empty( $this->db_table->get_prefixed_meta_table_name() ) &&
			! empty( $this->db_table->get_meta_table_relationship_field_name() )
		) {
			$where['meta_query']['metatable']           = $this->db_table->get_prefixed_meta_table_name();
			$where['meta_query']['relationship_column'] = $this->db_table->get_meta_table_relationship_field_name();
		}

		$rows = $this->db_handler->get_results(
			$this->db_table->get_prefixed_table_name(),
			$where,
			$columns,
			$per_page,
			( $page - 1 ) * $per_page
		);

		if ( empty( $rows ) ) {
			return [];
		}

		try {
			return array_map(
				function ( $data ) use ( $model ) {
					$object = $this->container->make( $model );
					$object->hydrate( $data );

					return $object;
				},
				$rows
			);
		} catch ( Exception $exception ) {
			return [];
		}
	}

	/**
	 * Count the number of rows based on the given parameters.
	 *
	 * @param array $where Filtering conditions.
	 *
	 * @return int The number of rows.
	 */
	protected function count_objects( array $where = [] ): int {
		return $this->db_handler->count(
			$this->db_table->get_prefixed_table_name(),
			$where
		);
	}
}
