<?php
namespace DevOwl\SearchEnginePostType;

use Exception;
use MatthiasWeb\Utils\Service;
use WP_REST_Response;
use WP_Error;

/**
 * Provide a common REST API endpoint for the endpoint.
 */
class RestService {
    use UtilsProvider;

    const NAMESPACE = 'search-engine-post-type/v1';

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

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

        $this->hooks();
    }

    /**
     * Create hooks to listen to changes.
     */
    public function hooks() {
        add_action('rest_api_init', [$this, 'rest_api_init']);
    }

    /**
     * Register endpoints.
     */
    public function rest_api_init() {
        $namespace = Service::getNamespace($this);
        $name = $this->getSearchEnginePostType()->getArg('name');

        register_rest_route($namespace, sprintf('/%s/query', $name), [
            'methods' => 'GET',
            'callback' => [$this, 'routeGet'],
            'permission_callback' => '__return_true',
            'args' => [
                'term' => [
                    'type' => 'string',
                    'required' => true,
                ],
                'hitsPerPage' => [
                    'type' => 'number',
                ],
                'taxonomy' => [
                    'type' => 'string',
                    'default' => '',
                ],
                'slugs' => [
                    'type' => 'string',
                    'default' => '',
                ],
            ],
        ]);
    }

    /**
     * See API docs.
     *
     * @param WP_REST_Request $request
     * @api {get} /search-engine-post-type/v1/your-registered-name/query Query a registered search for a post type
     * @apiParam {string} term
     * @apiParam {number} [hitsPerPage] Filter within a given taxonomy
     * @apiParam {string} [taxonomy] Filter within a given taxonomy
     * @apiParam {string} [slugs] If using `taxonomy`, provide a comma separated list of allowed slugs within this taxonomy
     * @apiName Get
     * @apiGroup SearchEnginePostType
     * @apiVersion 1.0.0
     */
    public function routeGet($request) {
        $searchEnginePostType = $this->getSearchEnginePostType();
        $term = $request->get_param('term');
        $hitsPerPage = $request->get_param('hitsPerPage');
        $taxonomy = $request->get_param('taxonomy');
        $slugs = $request->get_param('slugs');

        $args = [];

        if (!empty($hitsPerPage)) {
            $args['hitsPerPage'] = $hitsPerPage;
        }

        try {
            if (!empty($taxonomy) && !empty($slugs)) {
                $result = $searchEnginePostType
                    ->getProvider()
                    ->searchByTaxonomy($term, $taxonomy, explode(',', $slugs), $args);
            } else {
                $result = $searchEnginePostType->search($term, $args);
            }

            return new WP_REST_Response($result);
        } catch (Exception $e) {
            return new WP_Error('search_failed', $e->getMessage());
        }
    }

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