<?php
namespace DevOwl\SearchEnginePostType;

use WP_Error;
use WP_Post;

/**
 * Abstract search engine class to do things like creating index, search index by term
 * and persist record.
 */
abstract class AbstractSearchEngine {
    use UtilsProvider;

    /**
     * The post type instance.
     *
     * @var SearchEnginePostType
     */
    private $searchEnginePostType;

    /**
     * C'tor.
     *
     * @param SearchEnginePostType $searchEnginePostType
     * @codeCoverageIgnore
     */
    public function __construct($searchEnginePostType) {
        $this->searchEnginePostType = $searchEnginePostType;
    }

    /**
     * Search by a term and additional arguments. The arguments differ from provider to provider, but there
     * are "known" arguments which you should definitely implement in your class:
     *
     * - `hitsPerPage`
     *
     * @param string $term
     * @param array $args
     * @return Result|WP_Error
     */
    abstract public function search($term, $args = []);

    /**
     * Search by a term in a taxonomy and additional arguments. The arguments differ from provider to provider, but there
     * are "known" arguments which you should definitely implement in your class: See `search` method for more information.
     *
     * @param string $term
     * @param string $taxonomy
     * @param string[] $slugs The slugs for this taxonomy
     * @param array $args
     * @return Result|WP_Error
     */
    abstract public function searchByTaxonomy($term, $taxonomy, $slugs, $args = []);

    /**
     * Parse additional arguments for this search engine.
     *
     * @param array $args
     */
    abstract public function parseArguments($args);

    /**
     * Get the key for the unique ID key. For Algolia it is `objectID`.
     *
     * @return string
     */
    abstract public function getObjectIdKey();

    /**
     * Get the key for the distinct key. For Algolia it is `distinct_key`.
     * If set, the content is split into multiple records to keep the length
     * small. If `false`, the splitter is disabled.
     *
     * @return string|false
     */
    public function getDistinctKey() {
        return false;
    }

    /**
     * Validate additional arguments for this search engine.
     *
     * @param array $args
     * @throws Exception
     */
    abstract public function validateArguments($args);

    /**
     * Map a post so it can be finally created in the search engine.
     *
     * @param WP_Post $post
     * @param array $postArray
     */
    abstract public function mapPost($post, &$postArray);

    /**
     * Clear the index.
     */
    abstract public function clearIndex();

    /**
     * Put a set of post records to the index.
     *
     * @param array[] $posts
     */
    abstract public function putIndex(&$posts);

    /**
     * Remove a set of post IDs from the index. It also needs to consider the distinct key.
     *
     * @param int[] $ids
     */
    abstract public function removeFromIndex($ids);

    /**
     * Configure the current index.
     */
    abstract protected function configureIndex();

    /**
     * Configure the indexes. It also iterates all languages if active.
     */
    public function configureIndexes() {
        SearchEnginePostType::log(
            sprintf('Start configuring post type %s...', $this->getSearchEnginePostType()->getArg('post_type'))
        );
        $compLanguage = $this->getSearchEnginePostType()->getCompLanguage();
        if ($compLanguage !== null && $compLanguage->isActive()) {
            $compLanguage->iterateAllLanguagesContext(function () {
                $this->configureIndex();
            });
        } else {
            $this->configureIndex();
        }
    }

    /**
     * Get the language configured for the index. This returns the language as two-letter code.
     */
    public function getIndexLanguage() {
        $compLanguage = $this->getSearchEnginePostType()->getCompLanguage();
        if ($compLanguage !== null && $compLanguage->isActive()) {
            $language = $compLanguage->getCurrentLanguage();
        } else {
            $language = get_locale();
        }

        return preg_split('/[-_]/', $language, -1)[0];
    }

    /**
     * Getter.
     *
     * @codeCoverageIgnore
     */
    public function getSearchEnginePostType() {
        return $this->searchEnginePostType;
    }
}
