<?php

namespace Velis\Lang\LangVariant;

use Psr\SimpleCache\InvalidArgumentException;
use Velis\App;
use Velis\Db\Db;
use Velis\Lang\LangVariant;

/**
 * @author Damian Kurek <damian.kurek@velistech.com>
 */
class OverloadedLangs
{
    /**
     * Buffered langs.
     * @var OverloadedLang[]
     */
    private ?array $langs = null;
    protected Db $db;

    protected LangVariant $variant;

    /**
     * @var OverloadedLangs[]
     */
    protected static array $instances = [];
    /**
     * Hash of the currently chosen variant.
     * Variant set while creating the instance.
     */
    protected static string $variantHash = '';

    public function __construct(LangVariant $variant, Db $db)
    {
        $this->variant = $variant;
        $this->db = $db;
        $this->langs = null;
    }

    /**
     * Get a new OverloadedLangs instance if the variant has changed (or instance did not exist yet),
     * or get an existing one.
     */
    public static function load(LangVariant $variant, Db $db): OverloadedLangs
    {
        $variantAcro = $variant->getAcro();
        // If no instance exists, create a new one.
        if (!self::$instances[$variantAcro] instanceof OverloadedLangs) {
            self::$instances[$variantAcro] = new OverloadedLangs($variant, $db);
        }

        return self::$instances[$variantAcro];
    }

    /**
     * Fetch overloaded langs from the database - or from the cache if available.
     * @return OverloadedLang[]
     * @throws InvalidArgumentException
     */
    protected function fetchOverloadedLangs(): array
    {
        if (!App::$cache->has($this->getCacheKey())) {
            $query = "SELECT lk1.lang_group_id,
                             lk2.lang_key_id,
                             lk1.lang_key_id AS overloaded_lang_key_id
                        FROM app.lang_key_tab lk1
                             JOIN app.lang_key_tab lk2 ON lk1.lang_group_id = lk2.lang_group_id                         
                             AND lk1.lang_key_id = lk2.lang_key_id || :variant";

            $result = $this->db->getAll(
                $query,
                ['variant' => '_' . $this->variant->getAcro()],
            );

            $overloadedLangs = [];

            foreach ($result as $item) {
                $overloadedLangs[] = new OverloadedLang(
                    $item['lang_group_id'],
                    $item['lang_key_id'],
                    $item['overloaded_lang_key_id']
                );
            }
            App::$cache[$this->getCacheKey()] = $overloadedLangs;
        }
        return App::$cache[$this->getCacheKey()] ?? [];
    }

    /**
     * Get overloaded langs.
     * They should be fetched from the database (or from cache) only once.
     * Possible to fetch a fresh list, if needed, by passing `$fresh = true` as an argument.
     * @return OverloadedLang[]
     */
    public function get(bool $fresh = false): array
    {
        if (!is_array($this->langs) || $fresh) {
            $this->langs = $this->fetchOverloadedLangs();
        }

        return $this->langs ?? [];
    }


    /**
     * @return string
     */
    protected function getCacheKey(): string
    {
        return 'lang_variant_cache_' . $this->variant->getAcro();
    }


    /**
     * @return void
     */
    public function clearCache(): void
    {
        App::$cache->delete($this->getCacheKey());
    }
}
