<?php
declare(strict_types=1);
namespace Aen\Console;
use Symfony\Component\Console\Application;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Style\SymfonyStyle;
final class Factory
{
    public static function create(string $project,?string $runtime=null): Application
    {
        $app=new Application('AEN Console Workshop','1.0.0');$repo=new Repository($runtime??$project.'/runtime');
        $app->register('app:greet')->setDescription('Приветствие: аргумент и флаг.')->addArgument('name',InputArgument::REQUIRED,'Имя пользователя')->addOption('uppercase',null,InputOption::VALUE_NONE,'Верхний регистр')->setCode(function(InputInterface $in,OutputInterface $out):int{
            $name=trim((string)$in->getArgument('name'));if($name===''||mb_strlen($name)>80){self::error($out,'Имя должно содержать от 1 до 80 символов.');return Command::INVALID;}
            $message='Здравствуйте, '.$name.'!';$out->writeln($in->getOption('uppercase')?mb_strtoupper($message):$message,OutputInterface::OUTPUT_RAW);return Command::SUCCESS;
        });
        $app->register('contacts:import')->setDescription('Проверить CSV и импортировать только в runtime проекта.')->addArgument('file',InputArgument::REQUIRED,'CSV с name,email,city')->addOption('dry-run',null,InputOption::VALUE_NONE,'Проверить без изменения файлов')->setCode(function(InputInterface $in,OutputInterface $out)use($repo):int{
            try{$rows=$repo->csv((string)$in->getArgument('file'));}catch(\Throwable $e){self::error($out,$e->getMessage());return Command::INVALID;}
            try{$result=$repo->import($rows,(bool)$in->getOption('dry-run'));self::json($out,['mode'=>$in->getOption('dry-run')?'dry-run':'write',...$result]);return Command::SUCCESS;}catch(\Throwable $e){self::error($out,$e->getMessage());return Command::FAILURE;}
        });
        $app->register('contacts:report')->setDescription('Отчёт локальных контактов: JSON или таблица.')->addOption('format',null,InputOption::VALUE_REQUIRED,'json или table','table')->addOption('city',null,InputOption::VALUE_REQUIRED,'Город; пусто — все','')->setCode(function(InputInterface $in,OutputInterface $out)use($repo):int{
            if(!in_array($in->getOption('format'),['json','table'],true)){self::error($out,'Формат должен быть json или table.');return Command::INVALID;}
            $city=(string)$in->getOption('city');if($city!==''&&!in_array($city,['Москва','Казань','Тверь'],true)){self::error($out,'Неизвестный город.');return Command::INVALID;}
            try{$rows=array_values(array_filter($repo->read(),fn($row)=>$city===''||$row['city']===$city));if($in->getOption('format')==='json')self::json($out,['count'=>count($rows),'contacts'=>$rows]);else(new SymfonyStyle($in,$out))->table(['Имя','Email','Город'],array_map(fn($row)=>[$row['name'],$row['email'],$row['city']],$rows));return Command::SUCCESS;}catch(\Throwable $e){self::error($out,$e->getMessage());return Command::FAILURE;}
        });
        $app->register('batch:process')->setDescription('Учебная обработка с прогрессом в stderr и JSON в stdout.')->addOption('count',null,InputOption::VALUE_REQUIRED,'Количество от 1 до 50','8')->addOption('fail-at',null,InputOption::VALUE_REQUIRED,'Учебная ошибка на шаге; 0 — без ошибки','0')->setCode(function(InputInterface $in,OutputInterface $out):int{
            $count=filter_var($in->getOption('count'),FILTER_VALIDATE_INT);$fail=filter_var($in->getOption('fail-at'),FILTER_VALIDATE_INT);if($count===false||$count<1||$count>50||$fail===false||$fail<0||$fail>$count){self::error($out,'count: 1–50; fail-at: от 0 до count.');return Command::INVALID;}
            $err=self::stderr($out);$bar=new ProgressBar($err,$count);$bar->setFormat('normal');$bar->start();
            for($i=1;$i<=$count;$i++){if($i===$fail){$err->writeln('');self::error($out,'Учебный сбой на шаге '.$i.'. Повтор автоматически не запускается.');return Command::FAILURE;}$bar->advance();}
            $bar->finish();$err->writeln('');self::json($out,['processed'=>$count,'status'=>'complete']);return Command::SUCCESS;
        });
        $app->register('demo:confirm')->setDescription('Безопасное подтверждение учебного плана; ничего не удаляет.')->addOption('yes','y',InputOption::VALUE_NONE,'Явно подтвердить план')->setCode(function(InputInterface $in,OutputInterface $out):int{
            if(!$in->getOption('yes')){if(!$in->isInteractive()){self::error($out,'Для автоматического запуска требуется --yes; план не применён.');return Command::INVALID;}$io=new SymfonyStyle($in,$out);if(!$io->confirm('Подтвердить учебный план? Файлы не удаляются.',false)){$out->writeln('Отменено. Изменений нет.');return Command::FAILURE;}}
            $out->writeln('Учебный план подтверждён. Файлы не удалялись.');return Command::SUCCESS;
        });
        $app->register('app:config')->setDescription('Проверить переменные окружения без вывода секретов.')->setCode(function(InputInterface $in,OutputInterface $out):int{
            $rawEnv=getenv('APP_ENV');$env=$rawEnv===false?'dev':$rawEnv;$raw=getenv('APP_DEBUG');if(!in_array($env,['dev','test','prod'],true)||($raw!==false&&!in_array($raw,['0','1','true','false'],true))){self::error($out,'APP_ENV: dev/test/prod; APP_DEBUG: 0/1/true/false.');return Command::INVALID;}$debug=$raw==='1'||$raw==='true';self::json($out,['environment'=>$env,'debug'=>$debug,'dotenvAutoLoaded'=>false]);return Command::SUCCESS;
        });
        $app->register('demo:fail')->setDescription('Явная проверка exit code и stderr.')->addOption('kind',null,InputOption::VALUE_REQUIRED,'invalid или runtime','runtime')->setCode(function(InputInterface $in,OutputInterface $out):int{
            $kind=(string)$in->getOption('kind');if($kind==='invalid'){self::error($out,'Неверные входные параметры. Exit 2.');return Command::INVALID;}if($kind==='runtime'){self::error($out,'Учебная ошибка выполнения. Exit 1.');return Command::FAILURE;}self::error($out,'kind: invalid или runtime.');return Command::INVALID;
        });
        return $app;
    }
    private static function stderr(OutputInterface $out):OutputInterface{return $out instanceof ConsoleOutputInterface?$out->getErrorOutput():$out;}
    private static function error(OutputInterface $out,string $message):void{self::stderr($out)->writeln('Ошибка: '.$message,OutputInterface::OUTPUT_RAW);}
    private static function json(OutputInterface $out,array $data):void{$out->writeln(json_encode($data,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT|JSON_THROW_ON_ERROR),OutputInterface::OUTPUT_RAW);}
}
