<?php
// https://www.drupal.org/docs/8/modules/search-api/developer-documentation/executing-a-search-in-code

namespace Drupal\ouatt_searchapi\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Component\Utility\Tags;
use Drupal\Component\Utility\Unicode;
use Drupal\search_api\Entity\Index;

// https://drupal.stackexchange.com/questions/225008/programatically-use-search-api

/**
 * Defines a route controller for materio sapi search (regular and ajax).
 */
class Search extends ControllerBase {

  private $content_type;
  private $index;
  private $results;
  private $or_query;
  private $phrase;
  private $keys;
  private $offset;
  private $limit;

  // private $limit = 15;
  // private $offset = 0;

  private function sapiQuery(){
    // https://www.drupal.org/docs/8/modules/search-api/developer-documentation/executing-a-search-in-code
    // https://www.hashbangcode.com/article/drupal-8-date-search-boosting-search-api-and-solr-search
    // https://kgaut.net/blog/2018/drupal-8-search-api-effectuer-une-requete-dans-le-code.html

    // todo choose index regarding the content_type param
    if ($this->content_type === 'entites') {
      $this->index = Index::load('entites');
    }else{
      $this->index = Index::load('concernements');
    }

    $this->results = [
      'uuids' => [],
      'nids' => []
    ];             
                                                                  
    $this->or_query = $this->index->query(['offset'=>0,'limit'=>10000]);

    // Change the parse mode for the search.
    // Les différentes possibilités sont
    //  - « direct » => Requête directe
    //  - « terms » => Multiple words
    //  - « phrase » => Single phrase
    //  - " edismax " => ???
    $or_parse_mode = \Drupal::service('plugin.manager.search_api.parse_mode')
      ->createInstance('phrase');
    $or_parse_mode->setConjunction('OR');
    $this->or_query->setParseMode($or_parse_mode);

    // Set fulltext search keywords and fields.
    if ($this->keys) {
      $this->or_query->keys(implode(' ', $this->keys));
    }

    // if ($this->filters) {
    //   // FILTERS
    //   $or_filters_conditions = $this->or_query->createConditionGroup('OR');
    //   foreach ($this->filters as $filter) {
    //     $filter = (int) $filter;
    //     foreach (['thesaurus_tid'] as $field) { // 'tag_tid', 
    //       $or_filters_conditions->addCondition($field, $filter);
    //     }
    //   }
    //   $this->or_query->addConditionGroup($or_filters_conditions);

    //   if(!$this->keys) {
    //     // if no keys but filters switch query to direct and add wildcard solr keys *:* 
    //     $direct_or_parse_mode = \Drupal::service('plugin.manager.search_api.parse_mode')
    //     ->createInstance('direct');
    //     $direct_or_parse_mode->setConjunction('OR');
    //     $this->or_query->setParseMode($direct_or_parse_mode);
    //     // $this->or_query->keys('*:*');
    //   }

    // }

    // Add sorting.
    $this->or_query->sort('search_api_relevance', 'DESC');

    // Set one or more tags for the query.
    // @see hook_search_api_query_TAG_alter()
    // @see hook_search_api_results_TAG_alter()
    $this->or_query->addTag('ouatt_searchapi_search_or_query');

    $or_results = $this->or_query->execute();

    foreach ($or_results as $result) {
      $nid = $result->getField('nid')->getValues()[0];
      // !! have to remove duplicates instead of $exclude_and_results_conditions (solr too many boolean clauses)
      if ( !in_array($nid, $this->results['nids']) ) {
        $this->results['uuids'][] = $result->getField('uuid')->getValues()[0];
        $this->results['nids'][] = $nid;
      }
    }

  }

  /**
   * get params from request
   */
  private function parseRequest(Request $request){
    // Get the typed string from the URL, if it exists.
    $this->phrase = $request->query->get('phrase');
    if($this->phrase){
      $this->keys = mb_strtolower($this->phrase);
      $this->keys = Tags::explode($this->keys);
      // \Drupal::logger('ouatt_searchapi')->notice($this->keys);
    }
    
    $this->content_type = $request->query->get('content_type');
    // $this->content_type = $ct && strlen($ct) ? json_decode($ct) : null;

    
  }

  /**
   * Handler for ajax search.
   */
  public function getResults(Request $request) {
    $this->parseRequest($request);

    $resp = [];

    if ($this->keys) {
      
      $this->sapiQuery();

      $resp['content_type'] = $this->content_type;
      
      $resp['count'] = count($this->results['nids']);

      $resp['nids'] = array_slice($this->results['nids'], $this->offset, $this->limit);
      $resp['uuids'] = array_slice($this->results['uuids'], $this->offset, $this->limit);
    }
    return new JsonResponse($resp);
  }

}
