<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Dotenv\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
use Symfony\Component\Dotenv\Dotenv;

/**
 * A console command to compile .env files into a PHP-optimized file called .env.local.php.
 *
 * @internal
 */
#[Autoconfigure(bind: ['$dotenvPath' => '%kernel.project_dir%/.env', '$defaultEnv' => '%kernel.environment%'])]
#[AsCommand(name: 'dotenv:dump', description: 'Compiles .env files to .env.local.php')]
final class DotenvDumpCommand extends Command
{
    private $dotenvPath;
    private $defaultEnv;

    public function __construct(string $dotenvPath, string $defaultEnv = null)
    {
        $this->dotenvPath = $dotenvPath;
        $this->defaultEnv = $defaultEnv;

        parent::__construct();
    }

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this
            ->setDefinition([
                new InputArgument('env', null === $this->defaultEnv ? InputArgument::REQUIRED : InputArgument::OPTIONAL, 'The application environment to dump .env files for - e.g. "prod".'),
            ])
            ->addOption('empty', null, InputOption::VALUE_NONE, 'Ignore the content of .env files')
            ->setHelp(<<<'EOT'
The <info>%command.name%</info> command compiles .env files into a PHP-optimized file called .env.local.php.

    <info>%command.full_name%</info>
EOT
            )
        ;
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $env = $input->getArgument('env') ?? $this->defaultEnv;

        if ($input->getOption('empty')) {
            $vars = ['APP_ENV' => $env];
        } else {
            $vars = $this->loadEnv($env);
            $env = $vars['APP_ENV'];
        }

        $vars = var_export($vars, true);
        $vars = <<<EOF
<?php

// This file was generated by running "php bin/console dotenv:dump $env"

return $vars;

EOF;
        file_put_contents($this->dotenvPath.'.local.php', $vars, \LOCK_EX);

        $output->writeln(sprintf('Successfully dumped .env files in <info>.env.local.php</> for the <info>%s</> environment.', $env));

        return 0;
    }

    private function loadEnv(string $env): array
    {
        $dotenv = new Dotenv();
        $composerFile = \dirname($this->dotenvPath).'/composer.json';
        $testEnvs = (is_file($composerFile) ? json_decode(file_get_contents($composerFile), true) : [])['extra']['runtime']['test_envs'] ?? ['test'];

        $globalsBackup = [$_SERVER, $_ENV];
        unset($_SERVER['APP_ENV']);
        $_ENV = ['APP_ENV' => $env];
        $_SERVER['SYMFONY_DOTENV_VARS'] = implode(',', array_keys($_SERVER));

        try {
            $dotenv->loadEnv($this->dotenvPath, null, 'dev', $testEnvs);
            unset($_ENV['SYMFONY_DOTENV_VARS']);

            return $_ENV;
        } finally {
            [$_SERVER, $_ENV] = $globalsBackup;
        }
    }
}
