<?php

class ProductSearch {
	
  private ?string $language;
  
  public function __construct(?string $language = null) {
  	$this->language = $language;
  }

  public function searchIds(PDO $pdo, string $query): array {
    $query = trim($query);
    if ($query === '') return [];

    $idsFromSku  = $this->searchBySku($pdo, $query);
    $idsFromContent = $this->searchByContent($pdo, $query);

    return array_values(array_unique(array_merge($idsFromSku, $idsFromContent)));
  }

  private function searchBySku(PDO $pdo, string $query): array {
    $like = '%'.$query.'%';
    $sql = "SELECT id FROM products WHERE c_active = '1' AND (sku = :q OR external_sku = :q OR sku LIKE :like OR external_sku LIKE :like)";
    $result = $pdo->prepare($sql);
    $result->bindValue(':q', $query);
    $result->bindValue(':like', $like);
    $result->execute();
    return $result->fetchAll(PDO::FETCH_COLUMN);
  }

  private function searchByContent(PDO $pdo, string $query): array {
    $boolean = $this->buildBooleanQuery($query);

    try {
      $sql = "SELECT DISTINCT products_content.id_module AS id
      				FROM products_content AS products_content
      				JOIN products AS products ON products.id = products_content.id_module
      				WHERE products.c_active = '1' ";
      if ($this->language !== null && $this->language !== '') $sql .= "AND products_content.language = :language ";
      $sql .= "AND MATCH(products_content.title, products_content.teaser, products_content.content, products_content.addition)
      				AGAINST(:boolean IN BOOLEAN MODE)";
      $result = $pdo->prepare($sql);
      if ($this->language !== null && $this->language !== '') $result->bindValue(':language', $this->language);
      $result->bindValue(':boolean', $boolean);
      $result->execute();
      return $result->fetchAll(PDO::FETCH_COLUMN);

    } catch (PDOException $e) {
    	return $this->searchByContentLike($pdo, $query);
    }
  }

  private function searchByContentLike(PDO $pdo, string $query): array {
    $sql = "SELECT DISTINCT products_content.id_module AS id
    				FROM products_content AS products_content
    				JOIN products AS products ON products.id = products_content.id_module
    				WHERE products.c_active = '1' ";
    if ($this->language !== null && $this->language !== '') $sql .= "AND products_content.language = :language ";
    $sql .= "AND (products_content.title LIKE :q OR products_content.teaser LIKE :q OR products_content.content LIKE :q OR products_content.addition LIKE :q)";
    $result = $pdo->prepare($sql);
    if ($this->language !== null && $this->language !== '') $result->bindValue(':language', $this->language);
    $result->bindValue(':q', '%'.$query.'%');
    $result->execute();
    return $result->fetchAll(PDO::FETCH_COLUMN);
  }

  private function buildBooleanQuery(string $q): string {
    $q = trim($q);
    if ($q === '') return '';

    preg_match_all('/"([^"]+)"|\S+/', $q, $m);
    $terms = $m[0] ?? [];

    $parts = [];
    foreach ($terms as $t) {
      $t = trim($t, " \t\n\r\0\x0B\"");
      if ($t === '') continue;
      $t = ltrim($t, '+-~<>');
      if (mb_strlen($t) <= 1) continue;

      if (strpos($t, ' ') !== false) {
      	$parts[] = '+("'.$t.'")';
      } else {
      	$parts[] = '+'.$t.'*';
      }
    }
    if (empty($parts)) return '+'.$q.'*';
    return implode(' ', $parts);
  }
}
