<?php

namespace CelerSearch\Builders;

use CelerSearch\DataTransfer\IndexSettings;
use CelerSearch\Interfaces\IIndexSettingsBuilder;
use CelerSearch\Interfaces\IObjectBuilder;
use CelerSearch\Vendor\IgniteKit\Validation\Rules\In;

class IndexSettingsBuilder implements IObjectBuilder, IIndexSettingsBuilder {

	protected array $searchable_attributes = [];
	protected array $filterable_attributes = [];

	protected ?string $primary_key = null;
	protected ?string $distinct_attribute = null;
	protected array $sortable_attributes = [];
	protected array $snippet_attributes = [];
	protected int $max_hits = 1000;

	// New settings
	protected bool $typo_enabled = true;
	protected int $typo_min_one = 5;
	protected int $typo_min_two = 9;
	protected array $typo_disable_words = [];
	protected array $typo_disable_fields = [];
	protected array $stop_words = [];
	protected int $facet_max_values = 100;
	protected array $ranking_rules = [];
	protected string $proximity_precision = 'byWord';
	protected array $token_separators = [];
	protected array $non_token_separators = [];


	/**
	 * Set up primary key
	 * @param string $attribute
	 *
	 * @return self
	 */
	public function primary_key(string $attribute) : self {
		$this->primary_key = $attribute;
		return $this;
	}

	/**
	 * Set up searchable attributes
	 *
	 * @param array $attributes
	 *
	 * @return self
	 */
	public function searchable_attributes( array $attributes ) : self {
		$this->searchable_attributes = $attributes;

		return $this;
	}

	/**
	 * Set up filterable attributes
	 *
	 * @param array $attributes
	 *
	 * @return self
	 */
	public function filterable_attributes( array $attributes ) : self {
		$this->filterable_attributes = $attributes;

		return $this;
	}

	/**
	 * Set up distinct attribute
	 *
	 * @param string $attribute
	 *
	 * @return self
	 */
	public function distinct_attribute( string $attribute ) : self {
		$this->distinct_attribute = $attribute;

		return $this;
	}

	/**
	 * Set up sortable attributes
	 *
	 * @param array $attributes
	 *
	 * @return self
	 */
	public function sortable_attributes( array $attributes ) : self {
		$this->sortable_attributes = $attributes;

		return $this;
	}

	/**
	 * Set up snippet attributes
	 *
	 * @param array $attributes
	 *
	 * @return self
	 */
	public function snippet_attributes( array $attributes ) : self {
		$this->snippet_attributes = $attributes;

		return $this;
	}

	/**
	 * The max hits returned
	 *
	 * @param $hits
	 *
	 * @return self
	 */
	public function max_hits( $hits ) : self {

		$this->max_hits = $hits;

		return $this;
	}

	/**
	 * Set typo tolerance enabled
	 *
	 * @param bool $enabled
	 *
	 * @return self
	 */
	public function typo_enabled( bool $enabled ): self {
		$this->typo_enabled = $enabled;

		return $this;
	}

	/**
	 * Set minimum word size for one typo
	 *
	 * @param int $size
	 *
	 * @return self
	 */
	public function typo_min_one( int $size ): self {
		$this->typo_min_one = $size;

		return $this;
	}

	/**
	 * Set minimum word size for two typos
	 *
	 * @param int $size
	 *
	 * @return self
	 */
	public function typo_min_two( int $size ): self {
		$this->typo_min_two = $size;

		return $this;
	}

	/**
	 * Set words to disable typos on
	 *
	 * @param array $words
	 *
	 * @return self
	 */
	public function typo_disable_words( array $words ): self {
		$this->typo_disable_words = $words;

		return $this;
	}

	/**
	 * Set fields to disable typos on
	 *
	 * @param array $fields
	 *
	 * @return self
	 */
	public function typo_disable_fields( array $fields ): self {
		$this->typo_disable_fields = $fields;

		return $this;
	}

	/**
	 * Set stop words
	 *
	 * @param array $words
	 *
	 * @return self
	 */
	public function stop_words( array $words ): self {
		$this->stop_words = $words;

		return $this;
	}

	/**
	 * Set maximum facet values
	 *
	 * @param int $max
	 *
	 * @return self
	 */
	public function facet_max_values( int $max ): self {
		$this->facet_max_values = $max;

		return $this;
	}

	/**
	 * Set ranking rules
	 *
	 * @param array $rules
	 *
	 * @return self
	 */
	public function ranking_rules( array $rules ): self {
		$this->ranking_rules = $rules;

		return $this;
	}

	/**
	 * Set proximity precision
	 *
	 * @param string $precision
	 *
	 * @return self
	 */
	public function proximity_precision( string $precision ): self {
		$this->proximity_precision = $precision;

		return $this;
	}

	/**
	 * Set token separators
	 *
	 * @param array $separators
	 *
	 * @return self
	 */
	public function token_separators( array $separators ): self {
		$this->token_separators = $separators;

		return $this;
	}

	/**
	 * Set non-token separators
	 *
	 * @param array $separators
	 *
	 * @return self
	 */
	public function non_token_separators( array $separators ): self {
		$this->non_token_separators = $separators;

		return $this;
	}

	/**
	 * Load settings from stored config array
	 *
	 * @param array $stored_settings
	 *
	 * @return self
	 */
	public function from_stored( array $stored_settings ): self {
		if ( isset( $stored_settings['typo_enabled'] ) ) {
			$this->typo_enabled = (bool) $stored_settings['typo_enabled'];
		}
		if ( isset( $stored_settings['typo_min_one'] ) ) {
			$this->typo_min_one = (int) $stored_settings['typo_min_one'];
		}
		if ( isset( $stored_settings['typo_min_two'] ) ) {
			$this->typo_min_two = (int) $stored_settings['typo_min_two'];
		}
		if ( isset( $stored_settings['typo_disable_words'] ) && is_array( $stored_settings['typo_disable_words'] ) ) {
			$this->typo_disable_words = $stored_settings['typo_disable_words'];
		}
		if ( isset( $stored_settings['typo_disable_fields'] ) && is_array( $stored_settings['typo_disable_fields'] ) ) {
			$this->typo_disable_fields = $stored_settings['typo_disable_fields'];
		}
		if ( isset( $stored_settings['stop_words'] ) && is_array( $stored_settings['stop_words'] ) ) {
			$this->stop_words = $stored_settings['stop_words'];
		}
		if ( isset( $stored_settings['max_hits'] ) ) {
			$this->max_hits = (int) $stored_settings['max_hits'];
		}
		if ( isset( $stored_settings['facet_max_values'] ) ) {
			$this->facet_max_values = (int) $stored_settings['facet_max_values'];
		}
		if ( isset( $stored_settings['ranking_rules'] ) && is_array( $stored_settings['ranking_rules'] ) ) {
			$this->ranking_rules = $stored_settings['ranking_rules'];
		}
		if ( isset( $stored_settings['proximity_precision'] ) ) {
			$this->proximity_precision = $stored_settings['proximity_precision'];
		}
		if ( isset( $stored_settings['token_separators'] ) && is_array( $stored_settings['token_separators'] ) ) {
			$this->token_separators = $stored_settings['token_separators'];
		}
		if ( isset( $stored_settings['non_token_separators'] ) && is_array( $stored_settings['non_token_separators'] ) ) {
			$this->non_token_separators = $stored_settings['non_token_separators'];
		}

		return $this;
	}

	/**
	 * Creates object
	 * @return IndexSettings
	 */
	public function build() : IndexSettings {
		$object = new IndexSettings();
		if ( ! empty( $this->primary_key ) ) {
			$object->set_primary_key( $this->primary_key );
		}
		$object->set_searchable_attributes( $this->searchable_attributes );
		$object->set_filterable_attributes( $this->filterable_attributes );
		$object->set_distinct_attribute( $this->distinct_attribute );
		$object->set_sortable_attributes( $this->sortable_attributes );
		$object->set_snippet_attributes( $this->snippet_attributes );
		$object->set_max_hits( $this->max_hits );

		// New settings
		$object->set_typo_enabled( $this->typo_enabled );
		$object->set_typo_min_one( $this->typo_min_one );
		$object->set_typo_min_two( $this->typo_min_two );
		$object->set_typo_disable_words( $this->typo_disable_words );
		$object->set_typo_disable_fields( $this->typo_disable_fields );
		$object->set_stop_words( $this->stop_words );
		$object->set_facet_max_values( $this->facet_max_values );
		$object->set_ranking_rules( $this->ranking_rules );
		$object->set_proximity_precision( $this->proximity_precision );
		$object->set_token_separators( $this->token_separators );
		$object->set_non_token_separators( $this->non_token_separators );

		return $object;
	}
}