<?php

namespace KupShop\FeedGeneratorBundle\ContextProperties;

use KupShop\FeedGeneratorBundle\Expressions\ExpressionObjectTrait;
use KupShop\FeedGeneratorBundle\Expressions\IExpressionObject;
use KupShop\FeedGeneratorBundle\Utils\IObjectInfo;
use KupShop\FeedGeneratorBundle\Utils\Map;
use KupShop\KupShopBundle\Util\StringUtil;

class UtilsContextProperty implements IContextProperty, IExpressionObject, IObjectInfo
{
    use ExpressionObjectTrait;

    /** @var array */
    protected $maps;

    /** @var Map */
    private $map;

    public function __construct(Map $map)
    {
        $this->map = $map;
    }

    /**
     * @private
     */
    public static function getName(): string
    {
        return 'utils';
    }

    /**
     * Přeložit zadaný klíč (key) na jinou hodnotu dle použitého slovníku (mapName).
     *
     * Např. <code>utils.map('sections_map1', section.id, section.path())</code>
     * Třetí parametr je volitelný. Slouží pouze pro orientaci v mapování (sloupec Popis).
     *
     * Volitelně můžete předat ještě čtvrtý parametr, jehož hodnota se použije, pokud překlad neexistuje, nebo je mapovaná hodnota prázdná.
     * Např. <code>utils.map('sections_map1', section.id, section.path(), 'záložní hodnota')</code>
     *
     * @param string $key // TODO: make $key required (?string $key) when on PHP 7.1
     *
     * @return string
     */
    public function map(string $mapName, ?string $key = null, ?string $description = null, ?string $fallback = null)
    {
        return $this->map->map($mapName, $key, $description, $fallback);
    }

    /**
     * Kontrola existence klíče (key) v dané mapě (mapName).
     *
     * @param string $key // TODO: make $key required (?string $key) when on PHP 7.1
     */
    public function mapContains(string $mapName, ?string $key = null): bool
    {
        return $this->map->mapContains($mapName, $key);
    }

    /**
     * Pouze vytáhne existující překlad daného klíče (key) a nepřidává nové záznamy do mapy.
     *
     * @param string $key // TODO: make $key required (?string $key) when on PHP 7.1
     */
    public function findInMap(string $mapName, ?string $key = null): string
    {
        return $this->map->findInMap($mapName, $key);
    }

    /**
     * Upraví vložený text na SEO friendly řetězec znaků.
     */
    public function slugify(string $string): string
    {
        $transliterator = \Transliterator::create('Any-Latin; NFD; [:Nonspacing Mark:] Remove; NFC;', \Transliterator::FORWARD);

        return StringUtil::slugify($transliterator->transliterate($string));
    }

    /**
     * Odstraní elementy z textu.
     *
     * Např.: <code>utils.strip_tags(description)</code>
     */
    public function strip_tags(?string $string, string $allowable_tags = ''): string
    {
        return isset($string) ? html_entity_decode(strip_tags($string, $allowable_tags)) : '';
    }

    /**
     * Upraví vložený objekt datumu (datetime) na zadaný formát (format). <a href="http://php.net/manual/en/function.date.php" target="_blank">Dokumentace</a>.
     *
     * @return string|null
     *
     * @deprecated in favor of utils.formatDatetime()
     */
    public function formatDate($datetime, string $format = 'Y-m-d H:i')
    {
        if (is_string($datetime)) {
            $datetime = date_create($datetime);
        }

        if (!($datetime instanceof \DateTimeInterface)) {
            return null;
        }

        return $datetime->format($format);
    }

    /** Zakódovat text pro použití v URL */
    public function urlencode(?string $string): string
    {
        return urlencode($string ?? '');
    }

    /** Naformátovat datum.
     *
     * Vlastní formát viz <a href="https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens" target="_blank">dokumentace Day.js</a>
     *
     * @implementedInJS
     */
    public function formatDateOnly($date, string $format = 'YYYY-MM-DD'): string
    {
        return '';
    }

    /** Naformátovat datum a čas.
     *
     * Vlastní formát viz <a href="https://day.js.org/docs/en/parse/string-format#list-of-all-available-parsing-tokens" target="_blank">dokumentace Day.js</a>
     *
     * @implementedInJS
     */
    public function formatDatetime($date, string $format = 'YYYY-MM-DD HH:mm'): string
    {
        return '';
    }

    /** Počítadlo.
     *
     * Provolání funkce přičte jedničku k hodnotě počítadla se zadaným názvem. Výsledné součty všech počítadel se po vygenerování kompletního feedu zobrazí v reportu.
     *
     * @implementedInJS
     */
    public function reportCounter(string $name): void
    {
    }

    /** Vráti objekt (seznam) zadaných položek indexovaných podle zvoleného pole dané položky.
     *
     * Např. <code>utils.index(deliveries, 'heureka_id')</code> vrátí seznam (objekt) doprav indexovaných podle heureka_id
     *
     * @implementedInJS
     */
    public function index($sourceList, string $fieldName): void
    {
    }

    /** Filtruje seznam položek pomocí vlastní filtrační funkce.
     *
     * Např. <code>utils.filter(deliveries, (item) => item.final_price < 70)</code> vrátí položky s final_price nižší než 70.
     *
     * Příklad s filtrační funkcí zohledňující klíč v původním seznamu: <code>utils.filter(deliveries, (item, index) => index.includes('Zasilkovna'))</code> vrátí položky s klíčem, který obsahuje 'Zasilkovna'.
     *
     * Poslední parametr <code>returnArray</code> není nutné uvádět, ale v případě potřeby lze uvedením false vynutit zachování klíčů z původního seznamu. Výsledek poté nebude obyčejný seznam, ale objekt.
     *
     * @implementedInJS
     */
    public function filter($sourceList, callable $filterFunction, bool $returnArray = true): void
    {
    }

    /** Filtruje seznam položek podle zadané hodnoty nebo podle seznamu možných hodnot.
     *
     * Např. <code>utils.filterField(deliveries, 'heureka_id', 'PPL')</code> vrátí položky s heureka_id rovno 'PPL'.
     *
     * Příklad s více hodnotami: <code>utils.filterField(deliveries, 'heureka_id', ['PPL', 'PPL_PARCELSHOP'])</code> vrátí položky s heureka_id rovno 'PPL' nebo 'PPL_PARCELSHOP'.
     *
     * Poslední parametr <code>returnArray</code> není nutné uvádět, ale v případě potřeby lze uvedením false vynutit zachování klíčů z původního seznamu. Výsledek poté nebude obyčejný seznam, ale objekt.
     *
     * @implementedInJS
     */
    public function filterField($sourceList, string $fieldName, mixed $value, bool $returnArray = true): void
    {
    }

    /** Seřadí seznam položek podle zadaného pole.
     *
     * Např. <code>utils.sort(deliveries, 'final_price')</code>
     *
     * Příklad seřazení sestupně: <code>utils.sort(deliveries, 'final_price', true)</code>
     *
     * @implementedInJS
     */
    public function sort($sourceList, string $fieldName, $descending = false): void
    {
    }

    /** MD5 hash.
     *
     * Např. <code>utils.md5('some_string')</code>
     */
    public function md5(string $string): string
    {
        return md5($string);
    }
}
