<?php

namespace CelerSearch\Factories;

use CelerSearch\DataTransfer\IndexConfig;
use CelerSearch\DataTransfer\ServiceConfig;
use CelerSearch\Exceptions\MissingIndexException;
use CelerSearch\Exceptions\MissingIndexServiceException;
use CelerSearch\Exceptions\MissingIndexSupportException;
use CelerSearch\Exceptions\MissingServiceInIndexSettings;
use CelerSearch\Indices\BaseIndex;
use CelerSearch\Indices\OrdersIndex;
use CelerSearch\Indices\PostsIndex;
use CelerSearch\Indices\ProductsIndex;
use CelerSearch\Indices\TestIndex;
use CelerSearch\Repositories\IndexRepository;

class IndexFactory {

	/**
	 * Creates BaseIndex object from database entry
	 *
	 * @param $id
	 *
	 * @return BaseIndex
	 *
	 * @throws MissingIndexException
	 * @throws MissingIndexServiceException
	 * @throws MissingIndexSupportException
	 */
	public static function create( $id ): BaseIndex {

		$repo   = new IndexRepository();
		$record = $repo->find( $id );

		if ( ! $record ) {
			throw new MissingIndexException();
		}

		if ( empty( $record->getServiceId() ) ) {
			throw new MissingIndexServiceException();
		}

		$index = self::get_supported_index( $record->getType() );

		if ( ! $index ) {
			throw new MissingIndexSupportException();
		}


		return ( new $index['model']( $record ) );

	}

	/**
	 * Returns index instance for testing
	 *
	 * @param ServiceConfig $service_config
	 *
	 * @return BaseIndex
	 * @throws MissingServiceInIndexSettings
	 */
	public static function create_for_testing( ServiceConfig $service_config ): BaseIndex {

		$index_config = new IndexConfig( (object) [
			'name' => 'Test Index',
			'type' => 'test',
			'slug' => 'test',
		] );

		return ( new TestIndex( $index_config, $service_config ) );

	}


	/**
	 * Returns the supported indices
	 *
	 * @param $type
	 *
	 * @return BaseIndex|null
	 */
	public static function get_supported_index( $type ) {

		$supported = self::get_supported_indices();
		foreach ( $supported as $index ) {
			if ( $index['type'] === $type ) {
				return $index;
			}
		}

		return null;

	}

	/**
	 * Returns the supported indices
	 * @return BaseIndex[]
	 */
	public static function get_supported_indices(): array {

		return apply_filters( 'celersearch_supported_indices', [
			[
				'name'   => __( 'Post Index', 'celersearch' ),
				'type'   => 'posts',
				'model'  => PostsIndex::class,
				'fields' => [
					[
						'label' => __( 'Post Types', 'celersearch' ),
						'name'  => 'post_types',
						'type'  => 'dropdown',
						'rules' => 'required',
                        'options' => function() {
                            $types = get_post_types( [ 'public' => true ], 'objects' );
                            return array_values( array_map( function( $type ) {
                                return [
                                    'label' => $type->labels->singular_name,
                                    'value' => $type->name,
                                    'searchable' => ! $type->exclude_from_search,
                                ];
                            }, $types ) );
                        },
                        'multiple' => true,
                        'quick_select' => 'searchable',
					]
				]
			],
			[
				'name'     => __( 'WooCommerce Products', 'celersearch' ),
				'type'     => 'products',
				'model'    => ProductsIndex::class,
				'requires' => function() {
					return class_exists( 'WooCommerce' );
				},
				'fields' => [
					[
						'label' => __( 'Exclude Sold Out Products', 'celersearch' ),
						'name'  => 'exclude_sold_out',
						'type'  => 'checkbox',
						'rules' => '',
					],
					[
						'label' => __( 'Exclude Hidden/Catalog-Only Products', 'celersearch' ),
						'name'  => 'exclude_catalog_visibility',
						'type'  => 'checkbox',
						'rules' => '',
					]
				]
			],
			[
				'name'     => __( 'WooCommerce Orders', 'celersearch' ),
				'type'     => 'orders',
				'model'    => OrdersIndex::class,
				'requires' => function() {
					return class_exists( 'WooCommerce' );
				},
				'fields' => [
					[
						'label'        => __( 'Order Statuses', 'celersearch' ),
						'name'         => 'order_statuses',
						'type'         => 'dropdown',
						'rules'        => '',
						'options'      => function() {
							if ( ! function_exists( 'wc_get_order_statuses' ) ) {
								return [];
							}
							$statuses = wc_get_order_statuses();
							return array_map( function( $label, $status ) {
								return [
									'label' => $label,
									'value' => $status,
								];
							}, $statuses, array_keys( $statuses ) );
						},
						'multiple'     => true,
						'quick_select' => null,
					],
				],
			]
		] );

	}

}