<?php

namespace engine;

use Sphinx;

class SphinxUtil
{
    public static function execute(string $sql) {
        $link = self::getLink();

        if (func_num_args() > 1) {
            $mark_count = substr_count($sql, '?');
            $positions = [];
            $last_pos = -1;
            for ($i = 0; $i < $mark_count; $i++) {
                $last_pos = strpos($sql, '?', $last_pos + 1);
                $positions[] = $last_pos;
            }
            for ($i = $mark_count - 1; $i >= 0; $i--) {
                $arg = func_get_arg($i + 1);
                if (is_string($arg))
                    $arg = self::normalize($arg);
                $v = '\''.$link->real_escape_string($arg).'\'';
                $sql = substr_replace($sql, $v, $positions[$i], 1);
            }
        }

        $q = $link->query($sql);

        $error = self::getError();
        if ($error)
            logError(__FUNCTION__, $error);

        return $q;
    }

    public static function getError() {
        $link = self::getLink(auto_create: false);
        return $link?->error;
    }

    public static function mkquery($q, array $opts = []) {
        $defaults = [
            'any_word' => false,
            'star' => false,
            'and' => false,
            'exact_first' => false
        ];
        $opts = array_merge($defaults, $opts);
        $q = preg_replace('/\s+/', ' ', $q);
        $q = self::normalize($q);
        $q = trim($q);
        $q = self::getClient()->escapeString($q);
        if ($opts['star']) {
            $words = explode(' ', $q);
            $words = array_map(fn($word) => $word.'*', $words);
            $q = implode(' ', $words);
        }
        if ($opts['any_word']) {
            $q = str_replace(' ', ' | ', $q);
        } else if ($opts['and']) {
            $q = str_replace(' ', ' AND ', $q);
        }
        if ($opts['exact_first']) {
            $q = '"^'.$q.'$" | "'.$q.'" | ('.$q.')';
        }
        return $q;
    }

    public static function getClient(): Sphinx\SphinxClient {
        static $cl = null;
        if (!is_null($cl))
            return $cl;
        return $cl = new Sphinx\SphinxClient;
    }

    protected static function normalize(string $origstr): string {
        $buf = preg_replace('/[Ёё]/iu', 'е', $origstr);
        if (!pcreNoError($buf, no_error: true)) {
            $origstr = mb_convert_encoding($origstr, 'UTF-8', 'UTF-8');
            $buf = preg_replace('/[Ёё]/iu', 'е', $origstr);
            pcreNoError($buf);
        }
        if ($buf === null) {
            logError(__METHOD__.': preg_replace() failed with error: '.preg_last_error().': '.preg_last_error_msg());
            $buf = $origstr;
        }
        return preg_replace('/[!\?]/', '', $buf);
    }

    protected static function getLink($auto_create = true) {
        global $config;

        /** @var ?\mysqli $link */
        static $link = null;
        if (!is_null($link) || !$auto_create)
            return $link;

        $link = new \mysqli();
        $link->real_connect(
            $config['sphinx']['host'],
            ini_get('mysql.default_user'),
            ini_get('mysql.default_password'),
            null,
            9306);
        $link->set_charset('utf8');

        return $link;
    }
}