<?php
declare( strict_types=1 );

namespace FiboFilters\Indexer;

use FiboFilters\Integrations\Multilingual;
use FiboFilters\Util\DbUtil;
use FiboFilters\WPDBException;

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

/**
 * Class AbstractDocument
 */
abstract class AbstractDocument {
	/** @var string */
	private $lang = '';

	/** @var string */
	private $post_type = '';

	/** @var int */
	private $ID = 0;

	/** @var int */
	private $parent_id = 0;

	/** @var array */
	private $data;

	/** @var array */
	private $config;

	/** @var array */
	protected $data_to_index;

	/** @var DbUtil */
	protected $db_util;

	/** @var Multilingual */
	protected $multilingual;

	public function __construct( array $data, DbUtil $db_util, Multilingual $multilingual, array $config = [] ) {
		$this->db_util      = $db_util;
		$this->multilingual = $multilingual;

		$this->data   = $data;
		$this->config = $config;
		$this->set_id();
		$this->set_parent_id();
		$this->set_post_type();
		$this->set_lang();

		$this->clear_data_before_indexing();
		$this->set_data_to_index( $this->get_data() );
	}

	private function set_id(): void {
		if ( ! empty( $this->data['ID'] ) ) {
			$this->ID = (int) $this->data['ID'];
		}
	}

	private function set_parent_id(): void {
		if ( ! empty( $this->data['parent_id'] ) ) {
			$this->parent_id = (int) $this->data['parent_id'];
		}
	}

	private function set_lang(): void {
		if ( ! empty( $this->data['lang'] ) ) {
			$this->lang = $this->data['lang'];
		} else {
			$this->lang = $this->multilingual->is_multilingual() ? $this->multilingual->get_post_language( $this->get_id(), $this->get_post_type() ) : '';
		}
	}

	private function set_post_type(): void {
		if ( ! empty( $this->data['post_type'] ) ) {
			$this->post_type = $this->data['post_type'];
		} else {
			$this->post_type = (string) get_post_type( $this->get_id() );
		}
	}

	/**
	 * Remove some data that are stored elsewhere and shouldn't be included as a part of the document data
	 *
	 * @return void
	 */
	protected function clear_data_before_indexing(): void {
		$keys = [ 'ID', 'parent_id', 'lang', 'post_type', 'product_type' ];

		foreach ( $this->data as $key => $value ) {
			if ( in_array( $key, $keys, true ) || strpos( $key, 'tmp_tax_pa' ) !== false ) {
				unset( $this->data[ $key ] );
			}
		}
	}

	public function get_id(): int {
		return $this->ID;
	}

	public function get_parent_id(): int {
		return $this->parent_id;
	}

	public function get_language(): string {
		return $this->lang;
	}

	public function get_post_type(): string {
		return $this->post_type;
	}

	public function get_data(): array {
		return $this->data;
	}

	public function get_data_to_index(): array {
		return $this->data_to_index;
	}

	protected function set_data_to_index( array $data ): void {
		$this->data_to_index = $data;
	}

	public function get_config(): array {
		return $this->config;
	}

	public function get_index_role(): string {
		return $this->config['index_role'] ?? 'main';
	}

	/**
	 * Save the document data to the index
	 *
	 * @param string $updated_date Date of update.
	 *
	 * @throws WPDBException DB exception.
	 */
	public function save( string $updated_date = '' ): void {
		$this->prepare_data_to_index();
		$this->save_data_to_index( $updated_date );
	}

	public function update( string $updated_date = '' ): void {
		$this->delete();
		$this->save( $updated_date );
	}

	abstract public function delete( string $updated_date = '' ): void;

	/**
	 * Prepare document data for indexing
	 */
	abstract public function prepare_data_to_index(): void;

	/**
	 * Proper operation of saving a document to the index
	 *
	 * @param string $updated_date Date of update.
	 *
	 * @throws WPDBException DB exception.
	 */
	abstract protected function save_data_to_index( string $updated_date = '' ): void;
}
