<?php

namespace CelerSearch\Builders;

use CelerSearch\DataTransfer\IndexResponses\ErrorResponse;
use CelerSearch\DataTransfer\IndexResponses\SearchResponse;
use CelerSearch\DataTransfer\IndexResponses\SuccessResponse;
use CelerSearch\DataTransfer\IndexResponses\ValueResponse;
use CelerSearch\Interfaces\IObjectBuilder;

class IndexResponseBuilder implements IObjectBuilder {

	// General
	protected int $response_code;
	protected array $response_body = [];
	protected mixed $error_code = null;
	protected string $error_message = '';
	protected string $method;

	// Search related
	protected array $hits;
	protected int $total_hits;
	protected int $total_pages;
	protected int $hits_per_page;
	protected int $current_page;
	protected array $facet_distribution = [];
	protected array $facet_stats = [];

	// Value related
	protected mixed $value;

	// Task related (for async operations)
	protected ?string $task_id = null;
	protected mixed $task_object = null;

	/**
	 * Coonstructor
	 *
	 * @param string $method
	 */
	public function __construct( string $method ) {
		$this->method( $method );
	}

	/**
	 * Set the method
	 *
	 * @param string $method
	 *
	 * @return $this
	 */
	public function method( string $method ): IndexResponseBuilder {
		$this->method = $method;

		return $this;
	}

	/**
	 * Set response code
	 *
	 * @param int $response_code
	 *
	 * @return $this
	 */
	public function response_code( int $response_code ): IndexResponseBuilder {
		$this->response_code = $response_code;

		return $this;
	}

	/**
	 * Set response body
	 *
	 * @param array|object $response_body Array or Task object from Meilisearch SDK
	 *
	 * @return $this
	 */
	public function response_body( array|object $response_body ): IndexResponseBuilder {
		// Meilisearch SDK returns Task objects for async operations - convert to empty array
		$this->response_body = is_array( $response_body ) ? $response_body : [];

		return $this;
	}

	/**
	 * Set error code
	 *
	 * @param mixed $error_code
	 *
	 * @return $this
	 */
	public function error_code( mixed $error_code ): IndexResponseBuilder {
		$this->error_code = $error_code;

		return $this;
	}

	/**
	 * Set error message
	 *
	 * @param mixed $error_message
	 *
	 * @return $this
	 */
	public function error_message( mixed $error_message ): IndexResponseBuilder {
		$this->error_message = $error_message;

		return $this;
	}

	/**
	 * Set hits
	 *
	 * @param array $items
	 *
	 * @return IndexResponseBuilder
	 */
	public function hits( array $items ) : self {
		$this->hits = $items;

		return $this;
	}

	/**
	 * Set total hits
	 *
	 * @param int $total
	 *
	 * @return IndexResponseBuilder
	 */
	public function total_hits( int $total ) : self {
		$this->total_hits = $total;

		return $this;
	}

	/**
	 * Set total pages
	 *
	 * @param int $total
	 *
	 * @return IndexResponseBuilder
	 */
	public function total_pages( int $total ) : self {
		$this->total_pages = $total;

		return $this;
	}

	/**
	 * Set hits per page
	 *
	 * @param int $hits
	 *
	 * @return IndexResponseBuilder
	 */
	public function hits_per_page( int $hits ) : self {
		$this->hits_per_page = $hits;

		return $this;
	}

	/**
	 * Set current page
	 *
	 * @param int $current
	 *
	 * @return IndexResponseBuilder
	 */
	public function current_page( int $current ) : self {
		$this->current_page = $current;

		return $this;
	}

	/**
	 * Set facet distribution
	 *
	 * @param array $facet_distribution
	 *
	 * @return $this
	 */
	public function facet_distribution( array $facet_distribution ) : self {
		$this->facet_distribution = $facet_distribution;

		return $this;
	}

	/**
	 * Set facet stats
	 *
	 * @param array $facet_stats
	 *
	 * @return $this
	 */
	public function facet_stats( array $facet_stats ) : self {
		$this->facet_stats = $facet_stats;

		return $this;
	}

	/**
	 * Set value
	 *
	 * @param mixed $value
	 *
	 * @return $this
	 */
	public function value( mixed $value ) : self {
		$this->value = $value;

		return $this;
	}

	/**
	 * Set task ID
	 *
	 * @param string|null $task_id
	 *
	 * @return $this
	 */
	public function task_id( ?string $task_id ): self {
		$this->task_id = $task_id;

		return $this;
	}

	/**
	 * Set task object
	 *
	 * @param mixed $task_object
	 *
	 * @return $this
	 */
	public function task_object( mixed $task_object ): self {
		$this->task_object = $task_object;

		return $this;
	}

	/**
	 * Builds the object
	 * @return ErrorResponse|SearchResponse|SuccessResponse|ValueResponse
	 */
	public function build() : ErrorResponse|SearchResponse|SuccessResponse|ValueResponse {

		if ( $this->response_code >= 200 && $this->response_code <= 299 ) {

			if ( 'search' === $this->method ) {
				$instance = new SearchResponse();
				$instance->set_hits( $this->hits );
				$instance->set_total_hits( $this->total_hits );
				$instance->set_total_pages( $this->total_pages );
				$instance->set_current_page( $this->current_page );
				$instance->set_hits_per_page( $this->hits_per_page );
				$instance->set_facet_distribution( $this->facet_distribution );
				$instance->set_facet_stats( $this->facet_stats );
			} else if ( 'count_items' === $this->method ) {
				$instance = new ValueResponse();
				$instance->set_value( $this->value );
			} else {
				$instance = new SuccessResponse();
			}
			$instance->set_response_body( $this->response_body );
			$instance->set_response_code( $this->response_code );

		} else {
			$instance = new ErrorResponse();
			$instance->set_error_code( $this->error_code );
			$instance->set_error_message( $this->error_message );
			$instance->set_response_code( $this->response_code );
			$instance->set_response_body( $this->response_body );
		}

		// Set task info for async operations
		if ( $this->task_id !== null ) {
			$instance->set_task_id( $this->task_id );
		}
		if ( $this->task_object !== null ) {
			$instance->set_task_object( $this->task_object );
		}

		return $instance;

	}


}