<?php
/**
 * Abstract index base class.
 *
 * Provides common functionality for index classes, including cache handling,
 * table name generation and context‑aware database connection selection.
 *
 * @package FiboFilters\Index
 */

declare( strict_types=1 );

namespace FiboFilters\Index;

use FiboFilters\Struct\QueryContext;
use FiboFilters\Util\Cache;
use FiboFilters\Util\DbUtil;
use FiboFilters\WP\WPDB;
use FiboFilters\WP\WPDBSecond;

/**
 * Class AbstractIndex
 *
 * @since 1.10.0
 */
abstract class AbstractIndex {

	/**
	 * Primary database connection based on global $wpdb object.
	 *
	 * @var WPDB
	 */
	protected WPDB $wpdb;

	/**
	 * Secondary database connection.
	 *
	 * @var WPDBSecond
	 */
	protected WPDBSecond $wpdb_second;

	/**
	 * Cache utility instance.
	 *
	 * @var Cache
	 */
	protected Cache $cache;

	/**
	 * Database utilities helper.
	 *
	 * @var DbUtil
	 */
	protected DbUtil $db_util;

	/**
	 * AbstractIndex constructor.
	 *
	 * @param Cache                    $cache Cache utility instance.
	 * @param \FiboFilters\Util\DbUtil $db_util Database utilities helper.
	 * @param WPDB                     $wpdb Primary database connection.
	 * @param WPDBSecond               $wpdb_second Secondary database connection.
	 */
	public function __construct(
		Cache $cache,
		DbUtil $db_util,
		WPDB $wpdb,
		WPDBSecond $wpdb_second
	) {
		$this->cache       = $cache;
		$this->db_util     = $db_util;
		$this->wpdb        = $wpdb;
		$this->wpdb_second = $wpdb_second;
	}

	/**
	 * Returns table type identifier. Available types:
	 *  - 'filters_valuelist'
	 *  - 'filters_doclist'
	 *  - 'filters_sources'
	 *  - 'filters_descriptors'
	 *
	 * @return string Table type slug.
	 */
	abstract public function get_table_type(): string;

	/**
	 * Returns cache group name.
	 *
	 * @return string Cache group.
	 */
	abstract public function get_cache_group(): string;

	/**
	 * Builds a full table name respecting language and index role.
	 *
	 * @param QueryContext $ctx Query context.
	 *
	 * @return string          Fully‑qualified table name.
	 */
	public function get_table_name( QueryContext $ctx ): string {
		return $this->db_util->get_table_name(
			$this->get_table_type(),
			$ctx->get_index_role(),
			$ctx->get_lang()
		);
	}

	/**
	 * Returns index role ('main' or 'tmp').
	 *
	 * @return string Index role slug.
	 */
	public function get_index_role(): string {
		$role = $this->context['index_role'] ?? '';

		return in_array( $role, [ 'tmp', 'main' ], true ) ? $role : 'main';
	}

	/**
	 * Creates suffix used in cache key generation.
	 * It takes into account the language, index role and database connection type, e.g: '_pl_tmp_wpdb_2nd'.
	 *
	 * @param QueryContext|null $ctx Query context.
	 *
	 * @return string               Cache‑key suffix.
	 */
	public function create_suffix_cache_key( ?QueryContext $ctx = null ): string {
		$base_key = '';
		$language = $ctx->get_lang();
		$index    = $ctx->get_index_role();

		$base_key .= $language ? '_' . $language : '';
		$base_key .= $index && $index !== 'main' ? '_' . $index : '';
		$base_key .= $ctx->is_wpdb_second() ? '_wpdb_2nd' : '';

		return $base_key;
	}

	/**
	 * Fetches items from cache.
	 *
	 * @param string            $cache_key Base cache key.
	 * @param QueryContext|null $ctx Query context.
	 *
	 * @return false|mixed False on failure to retrieve contents or the cache contents on success.
	 */
	protected function get_cached_items( string $cache_key, ?QueryContext $ctx = null ) {
		$ctx = $ctx ?? new QueryContext();

		$cache_key = $cache_key . $this->create_suffix_cache_key( $ctx );

		return $this->cache->get( $cache_key, $this->get_cache_group() );
	}

	/**
	 * Stores items in cache.
	 *
	 * @param string            $cache_key Base cache key.
	 * @param mixed             $items Data to cache.
	 * @param QueryContext|null $ctx Query context.
	 *
	 * @return void
	 */
	protected function set_cached_items( string $cache_key, $items, ?QueryContext $ctx = null ): void {
		$ctx = $ctx ?? new QueryContext();

		$cache_key = $cache_key . $this->create_suffix_cache_key( $ctx );

		$this->cache->set( $cache_key, $items, $this->get_cache_group() );
	}

	/**
	 * Returns database connection proper for given context.
	 *
	 * @param QueryContext $ctx Query context.
	 *
	 * @return WPDB|WPDBSecond  Database connection instance.
	 */
	public function get_wpdb( QueryContext $ctx ) {
		return $ctx->is_wpdb_second() ? $this->wpdb_second : $this->wpdb;
	}
}
