<?php
declare(strict_types=1);
namespace Aen\TwigWorkshop;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
use Twig\Error\Error as TwigError;

final class Workshop {
    public const TEMPLATES = [
        'card'=>'card.html.twig','list'=>'list.html.twig','layout'=>'overview.html.twig',
        'include'=>'team.html.twig','macro'=>'form.html.twig','email'=>'email.html.twig',
        'escape'=>'escape.html.twig','strict'=>'strict.html.twig','cache'=>'card.html.twig'
    ];
    public static function environment(bool $strict=true, string|false $cache=false): Environment {
        return new Environment(new FilesystemLoader(dirname(__DIR__).'/templates'), [
            'autoescape'=>'html','strict_variables'=>$strict,'cache'=>$cache,'auto_reload'=>true,
            'debug'=>false,'charset'=>'UTF-8',
        ]);
    }
    public static function run(string $scenario, array $data, array $options=[]): array {
        if(!isset(self::TEMPLATES[$scenario])) throw new \InvalidArgumentException('Неизвестный сценарий.');
        $strict=$options['strict']??true;
        if(!is_bool($strict)) throw new \InvalidArgumentException('strict должен быть true или false.');
        $template=self::TEMPLATES[$scenario];
        if($scenario==='layout' && ($options['page']??'overview')==='details') $template='details.html.twig';
        $twig=self::environment($strict);
        try {
            $html=$twig->render($template,$data);
            if(strlen($html)>131072) throw new \InvalidArgumentException('Результат превышает 128 КиБ.');
            $text=$scenario==='email'?$twig->render('email.txt.twig',$data):null;
            // Compile the same trusted template with ArrayLoader so the public
            // recording has no environment-specific absolute path or byte count.
            $compiler=$scenario==='cache'?new Environment(new \Twig\Loader\ArrayLoader([$template=>$twig->getLoader()->getSourceContext($template)->getCode()]),['autoescape'=>'html','strict_variables'=>$strict,'cache'=>false]):null;
            $compiled=$compiler?->compileSource($compiler->getLoader()->getSourceContext($template));
            return ['ok'=>true,'engine'=>'Twig PHP','version'=>Environment::VERSION,'scenario'=>$scenario,'template'=>$template,'strict'=>$strict,'html'=>$html,'text'=>$text,
                'details'=>['templateBytes'=>strlen($twig->getLoader()->getSourceContext($template)->getCode()),'outputBytes'=>strlen($html),'compiledBytes'=>$compiled===null?null:strlen($compiled),'publicCacheEnabled'=>false,'note'=>$scenario==='cache'?'Настоящая компиляция Twig без записи на диск. Кеш файлов проверяется локальной командой php bin/cache-demo.php.':'Шаблон фиксирован; данные существуют только в этом запросе.']];
        } catch(TwigError $e){
            return ['ok'=>false,'engine'=>'Twig PHP','version'=>Environment::VERSION,'scenario'=>$scenario,'template'=>$template,'strict'=>$strict,'code'=>'TEMPLATE_ERROR','message'=>$e->getRawMessage(),'line'=>$e->getTemplateLine()];
        }
    }
    public static function recipe(string $scenario, array $data, array $options): string {
        $encoded=base64_encode(json_encode($data,JSON_UNESCAPED_UNICODE|JSON_THROW_ON_ERROR));
        return "<?php\ndeclare(strict_types=1);\nrequire __DIR__.'/vendor/autoload.php';\nuse Aen\\TwigWorkshop\\Workshop;\n\$data=json_decode(base64_decode(".var_export($encoded,true)."),true,16,JSON_THROW_ON_ERROR);\n\$result=Workshop::run(".var_export($scenario,true).",\$data,".var_export($options,true).");\nif(!\$result['ok']){fwrite(STDERR,\$result['message'].PHP_EOL);exit(1);}\necho \$result['html'];\n";
    }
}
