<?php

namespace AppBundle\Translation;

use Symfony\Component\Translation\TranslatorInterface;

class ConstTranslator
{
    /**
     * @var TranslatorInterface
     */
    private $translator;

    /**
     * Constructor
     * 
     * @param TranslatorInterface $translator 
     */
    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }

    /**
     * Get the translations of the given class constants, according to their prefix.
     * The translation are retrieved from translation keys based on the class name and the constant name.
     * Example: the constant CERPEP from the DemandePEEType class will use the following translation key: word.type.demandePEE.cerpep.label
     *
     * @param string $classname Fully-qualified class name. The last Camel cased word of the short class name must be the descriptor of all the constants. Exemple: in the UserType class name, the word 'Type' is the descriptor of all the constants of this class.
     * @param array $args Optional parameters:
     * - string|array   $args[0] Restrict the constant to the ones with this (or these) value(s)
     * - string         $args[1] Translation suffix ('label' in the example above; this value is also the default if not provided)
     * - bool           $args[2] Translation domain. By default, use word domain.
     * - bool           $args[3] Add none default value
     *
     * @return array Format: [cName1 => cTranslation1, cName2 => cTranslation2]
     */
    public function trans(string $classname, ...$args): array
    {
        try {
            $rc = new \ReflectionClass($classname);
        } catch (\ReflectionException $e) {
            return [];
        }

        $classnameShort = $rc->getShortName();

        $constants = $translations = [];
        $translationKeySuffix = $args[1] ?? 'label';
        $translationDomain = $args[2] ?? 'word';

        // The list of constants is not restricted: retrieve all the constants
        if (0 === count($args) || $args[0] === null) { // 
            $constants = $rc->getConstants();
        }
        // The list of constants is restricted: filter the list of class constants to the ones that have the provided values
        else {
            if (is_array($args[0])) {
                $constants = array_intersect($constants, $args[0]);
            } elseif ($cName = array_search($args[0], $rc->getConstants(), true)) {
                $constants = [$cName => $args[0]];
            }
        }

        // Look for the first Uppercased character in the short class name, starting from the end
        // Example with 'DemandePEEType':
        // $i = 14
        // 1. Check the 'e'
        // 2. Check the 'p'
        // ...
        // 5. Check the 'T'
        // $i = 11
        $i = strlen($classnameShort);
        while (ctype_lower($classnameShort[--$i])) {}

        $cType = substr(lcfirst($classnameShort), 0, $i); // $cType = 'demandePEE'
        $cProperty = substr(mb_strtolower($classnameShort), $i); // $cType = 'type'

        if (!$constants) {
            $translations[] = '';
        } else {
            // @NOTE Add "none" default value
            if(isset($args[3]) && $args[3]) {
                $translations[''] = $this->findConstantTranslation("none", $cType, $cProperty, $translationKeySuffix, $translationDomain); 

                // if translation is not found, change to default label
                if (substr_count($translations[''], '.') == 4) {
                    $translations[''] = $this->translator->trans("form.choice.none.label", [], 'form');   
                }
            }

            foreach ($constants as $cName => $cValue) {
                $translations[$cValue] = $this->findConstantTranslation($cName, $cType, $cProperty, $translationKeySuffix, $translationDomain);
            }
        }

        return $translations;
    }

    /**
     * Find the translation of a constant
     * 
     * @param  string $cName
     * @param  string $cType
     * @param  string $cProperty
     * @param  string $tKeySuffix
     * @param  string $tDomain
     * 
     * @return string
     */
    private function findConstantTranslation(string $cName, string $cType, string $cProperty, string $tKeySuffix, string $tDomain = "word" ): string
    {
        // Example with the following fully-qualified classname AppBundle\Enum\DemandePEEType (constant: CERPEP):
        // word.type.demandePEE.cerpep.label
        $translationKey = join('.', [
            $tDomain,
            $cProperty,
            $cType,
            mb_strtolower($cName),
            $tKeySuffix
        ]);

        return $this->translator->trans($translationKey, [], $tDomain);
    }
}
