<?php

declare(strict_types=1);

namespace Cin\AjaxSearch5;

use Cin\AjaxSearch5\Logger as Log;
use PDO;
use TeamTNT\TNTSearch\TNTSearch;
use Throwable;

final class Search
{
  private TNTSearch $tnt;

  private ?string $cISO = null;

  private Plugin $P;

  public function __construct(?string $cISO = null)
  {
    $this->P = new Plugin();
    $cfg     = Config::create();
    if (null === $cISO) {
      $this->cISO = $this->getDefaultLanguage();
    } else {
      $this->cISO = $cISO;
    }
    Log::info('initializing search for '.$this->cISO);
    $this->tnt = new TNTSearch();
    $this->tnt->loadConfig([
      'driver'   => 'mysql',
      'host'     => $cfg['host'],
      'database' => $cfg['name'],
      'username' => $cfg['user'],
      'password' => $cfg['pass'],
      'storage'  => __DIR__.'/../indices/'
    ]);

    try {
      $this->tnt->selectIndex($this->cISO.'.index.sqlite3');
    } catch (Throwable $th) {
      Log::error('Search->selectIndex', $th->getMessage());
    }
  }

  public function search(string $term): array
  {
    $this->tnt->fuzziness      = true;
    $this->tnt->fuzzy_distance = (int) $this->P->cfg()['fuzzyness'];
    $this->tnt->prefix_length  = (int) floor($this->P->cfg()['minchars'] / 2);
    $this->tnt->max_expansions = (int) $this->P->cfg()['resultcount'];

    return $this->tnt->search($term, $this->P->cfg()['resultcount']);
  }

  private function getDefaultLanguage(): string
  {
    $list = $this->readLanguages();
    $lang = array_filter($list, static function ($entry) {
      return 'Y' === $entry['cShopStandard'];
    })[0];

    return $lang['cISO'];
  }

  private function readLanguages(): array
  {
    $cfg = Config::create();
    $db  = new PDO(
      'mysql:dbname='.$cfg['name'].';host='.$cfg['host'].';charset=utf8mb4',
      $cfg['user'],
      $cfg['pass'],
      [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ,
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_EMULATE_PREPARES   => false,
        PDO::ATTR_STRINGIFY_FETCHES  => false
      ]
    );
    $minor = (int) explode('.', \JTL\Shop::getApplicationVersion())[1];
    if (0 === $minor) {
      $stmt = $db->prepare('SELECT * FROM tsprache');
    } else {
      $stmt = $db->prepare('SELECT * FROM tsprache WHERE active=1');
    }
    $stmt->execute();

    return $stmt->fetchAll(PDO::FETCH_ASSOC);
  }
}
