<?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 Paysera\Scoped\Symfony\Component\Dotenv\Command;

use Paysera\Scoped\Symfony\Component\Console\Command\Command;
use Paysera\Scoped\Symfony\Component\Console\Formatter\OutputFormatter;
use Paysera\Scoped\Symfony\Component\Console\Input\InputInterface;
use Paysera\Scoped\Symfony\Component\Console\Output\OutputInterface;
use Paysera\Scoped\Symfony\Component\Console\Style\SymfonyStyle;
use Paysera\Scoped\Symfony\Component\Dotenv\Dotenv;
/**
 * A console command to debug current dotenv files with variables and values.
 *
 * @author Christopher Hertel <mail@christopher-hertel.de>
 */
final class DebugCommand extends Command
{
    protected static $defaultName = 'debug:dotenv';
    protected static $defaultDescription = 'Lists all dotenv files with variables and values';
    private $kernelEnvironment;
    private $projectDirectory;
    public function __construct(string $kernelEnvironment, string $projectDirectory)
    {
        $this->kernelEnvironment = $kernelEnvironment;
        $this->projectDirectory = $projectDirectory;
        parent::__construct();
    }
    protected function execute(InputInterface $input, OutputInterface $output) : int
    {
        $io = new SymfonyStyle($input, $output);
        $io->title('Dotenv Variables & Files');
        if (!\array_key_exists('SYMFONY_DOTENV_VARS', $_SERVER)) {
            $io->error('Dotenv component is not initialized.');
            return 1;
        }
        $dotenvPath = $this->projectDirectory;
        if (\is_file($composerFile = $this->projectDirectory . '/composer.json')) {
            $runtimeConfig = \json_decode(\file_get_contents($composerFile), \true)['extra']['runtime'] ?? [];
            if (isset($runtimeConfig['dotenv_path'])) {
                $dotenvPath = $this->projectDirectory . '/' . $runtimeConfig['dotenv_path'];
            }
        }
        $filePath = $dotenvPath . '/.env';
        $envFiles = $this->getEnvFiles($filePath);
        $availableFiles = \array_filter($envFiles, 'is_file');
        if (\in_array(\sprintf('%s.local.php', $filePath), $availableFiles, \true)) {
            $io->warning('Due to existing dump file (.env.local.php) all other dotenv files are skipped.');
        }
        if (\is_file($filePath) && \is_file(\sprintf('%s.dist', $filePath))) {
            $io->warning(\sprintf('The file %s.dist gets skipped due to the existence of %1$s.', $this->getRelativeName($filePath)));
        }
        $io->section('Scanned Files (in descending priority)');
        $io->listing(\array_map(function (string $envFile) use($availableFiles) {
            return \in_array($envFile, $availableFiles, \true) ? \sprintf('<fg=green>✓</> %s', $this->getRelativeName($envFile)) : \sprintf('<fg=red>⨯</> %s', $this->getRelativeName($envFile));
        }, $envFiles));
        $variables = $this->getVariables($availableFiles);
        $io->section('Variables');
        $io->table(\array_merge(['Variable', 'Value'], \array_map([$this, 'getRelativeName'], $availableFiles)), $variables);
        $io->comment('Note that values might be different between web and CLI.');
        return 0;
    }
    private function getVariables(array $envFiles) : array
    {
        $variables = [];
        $fileValues = [];
        $dotenvVars = \array_flip(\explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? ''));
        foreach ($envFiles as $envFile) {
            $fileValues[$envFile] = $this->loadValues($envFile);
            $variables += $fileValues[$envFile];
        }
        foreach ($variables as $var => $varDetails) {
            $realValue = $_SERVER[$var] ?? '';
            $varDetails = [$var, '<fg=green>' . OutputFormatter::escape($realValue) . '</>'];
            $varSeen = !isset($dotenvVars[$var]);
            foreach ($envFiles as $envFile) {
                if (null === ($value = $fileValues[$envFile][$var] ?? null)) {
                    $varDetails[] = '<fg=yellow>n/a</>';
                    continue;
                }
                $shortenedValue = OutputFormatter::escape($this->getHelper('formatter')->truncate($value, 30));
                $varDetails[] = $value === $realValue && !$varSeen ? '<fg=green>' . $shortenedValue . '</>' : $shortenedValue;
                $varSeen = $varSeen || $value === $realValue;
            }
            $variables[$var] = $varDetails;
        }
        \ksort($variables);
        return $variables;
    }
    private function getEnvFiles(string $filePath) : array
    {
        $files = [\sprintf('%s.local.php', $filePath), \sprintf('%s.%s.local', $filePath, $this->kernelEnvironment), \sprintf('%s.%s', $filePath, $this->kernelEnvironment)];
        if ('test' !== $this->kernelEnvironment) {
            $files[] = \sprintf('%s.local', $filePath);
        }
        if (!\is_file($filePath) && \is_file(\sprintf('%s.dist', $filePath))) {
            $files[] = \sprintf('%s.dist', $filePath);
        } else {
            $files[] = $filePath;
        }
        return $files;
    }
    private function getRelativeName(string $filePath) : string
    {
        if (\str_starts_with($filePath, $this->projectDirectory)) {
            return \substr($filePath, \strlen($this->projectDirectory) + 1);
        }
        return \basename($filePath);
    }
    private function loadValues(string $filePath) : array
    {
        if (\str_ends_with($filePath, '.php')) {
            return include $filePath;
        }
        return (new Dotenv())->parse(\file_get_contents($filePath));
    }
}
