<?php

declare(strict_types=1);

namespace App\Framework\Config\Console;

use App\Framework\Config\EncryptedEnvLoader;
use App\Framework\Config\Environment;
use App\Framework\Config\SecretManager;
use App\Framework\Console\ConsoleColor;
use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ConsoleOutput;
use App\Framework\Console\ExitCode;
use App\Framework\Encryption\EncryptionFactory;
use App\Framework\Random\RandomGenerator;

/**
 * Console commands for secrets management
 */
final readonly class SecretsCommand
{
    public function __construct(
        private RandomGenerator $randomGenerator,
        private EncryptionFactory $encryptionFactory,
        private ?SecretManager $secretManager = null
    ) {
    }

    #[ConsoleCommand('secrets:generate-key', 'Generate a secure encryption key')]
    public function generateKey(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $output->writeLine('🔐 Generating encryption key...', ConsoleColor::CYAN);
        $output->newLine();

        try {
            $length = 32;
            $keyBytes = $this->randomGenerator->bytes($length);
            $encodedKey = base64_encode($keyBytes);

            $availableMethods = $this->encryptionFactory->getAvailableMethods();
            $recommendedMethod = $this->encryptionFactory->getRecommendedMethod();

            $output->writeLine("Available methods: " . implode(', ', $availableMethods));
            $output->writeLine("Using recommended method: {$recommendedMethod}", ConsoleColor::GREEN);
            $output->newLine();

            $output->writeSuccess('✅ Encryption key generated successfully!');
            $output->newLine();
            $output->writeLine('ENCRYPTION_KEY=' . $encodedKey, ConsoleColor::YELLOW);
            $output->newLine();

            $output->writeWarning('🚨 SECURITY WARNINGS:');
            $output->writeLine('• Store this key securely - it cannot be recovered if lost');
            $output->writeLine('• Add this to your .env file (never commit to version control)');
            $output->writeLine('• Use different keys for different environments');
            $output->newLine();

            $output->writeInfo('📋 Next steps:');
            $output->writeLine('1. Add the key to your .env file');
            $output->writeLine('2. Create .env.secrets file: php console.php secrets:init');
            $output->writeLine('3. Encrypt secrets: php console.php secrets:encrypt "secret-value"');

            return ExitCode::SUCCESS;
        } catch (\Throwable $e) {
            $output->writeError('❌ Failed to generate encryption key: ' . $e->getMessage());

            return ExitCode::GENERAL_ERROR;
        }
    }

    #[ConsoleCommand('secrets:encrypt', 'Encrypt a secret value')]
    public function encrypt(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        if ($this->secretManager === null) {
            $output->writeError('❌ SecretManager not available. Make sure ENCRYPTION_KEY is set in .env');

            return ExitCode::CONFIG_ERROR;
        }

        $value = $input->getArgument(0);
        if (! $value) {
            $value = $output->askPassword('Enter secret value to encrypt:');
        }

        if (empty($value)) {
            $output->writeError('❌ No value provided to encrypt');

            return ExitCode::CONFIG_ERROR;
        }

        try {
            $encrypted = $this->secretManager->encryptSecret($value);

            $output->writeSuccess('✅ Value encrypted successfully!');
            $output->newLine();
            $output->writeLine('Encrypted value:', ConsoleColor::CYAN);
            $output->writeLine($encrypted, ConsoleColor::YELLOW);
            $output->newLine();
            $output->writeInfo('💡 Add this to your .env.secrets file like:');
            $output->writeLine('SECRET_YOUR_KEY=' . $encrypted, ConsoleColor::GRAY);

            return ExitCode::SUCCESS;
        } catch (\Throwable $e) {
            $output->writeError('❌ Failed to encrypt value: ' . $e->getMessage());

            return ExitCode::SOFTWARE_ERROR;
        }
    }

    #[ConsoleCommand('secrets:decrypt', 'Decrypt a secret value (for debugging)')]
    public function decrypt(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        if ($this->secretManager === null) {
            $output->writeError('❌ SecretManager not available. Make sure ENCRYPTION_KEY is set in .env');

            return ExitCode::CONFIG_ERROR;
        }

        $encryptedValue = $input->getArgument(0);
        if (! $encryptedValue) {
            $encryptedValue = $output->askQuestion('Enter encrypted value to decrypt:');
        }

        if (empty($encryptedValue)) {
            $output->writeError('❌ No encrypted value provided');

            return ExitCode::INVALID_INPUT;
        }

        try {
            if (! $this->secretManager->isEncrypted($encryptedValue)) {
                $output->writeWarning('⚠️  Value does not appear to be encrypted');

                return ExitCode::INVALID_INPUT;
            }

            $decrypted = $this->secretManager->getSecret('TEMP_DECRYPT', $encryptedValue);

            $output->writeSuccess('✅ Value decrypted successfully!');
            $output->newLine();
            $output->writeLine('Decrypted value:', ConsoleColor::CYAN);
            $output->writeLine($decrypted, ConsoleColor::YELLOW);
            $output->newLine();
            $output->writeWarning('🔒 This value should be kept secure!');

            return ExitCode::SUCCESS;
        } catch (\Throwable $e) {
            $output->writeError('❌ Failed to decrypt value: ' . $e->getMessage());

            return ExitCode::SOFTWARE_ERROR;
        }
    }

    #[ConsoleCommand('secrets:init', 'Initialize .env.secrets file')]
    public function init(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $basePath = getcwd();
        $secretsFile = $basePath . '/.env.secrets';

        if (file_exists($secretsFile)) {
            if (! $output->confirm('⚠️  .env.secrets already exists. Overwrite?', false)) {
                $output->writeInfo('Operation cancelled');

                return ExitCode::SUCCESS;
            }
        }

        try {
            $encryptedLoader = new EncryptedEnvLoader($this->encryptionFactory, $this->randomGenerator);
            $filePath = $encryptedLoader->generateSecretsTemplate($basePath);

            $output->writeSuccess('✅ .env.secrets template created!');
            $output->writeLine("File created at: {$filePath}", ConsoleColor::GRAY);
            $output->newLine();
            $output->writeInfo('📋 Next steps:');
            $output->writeLine('1. Edit .env.secrets and add your secret keys');
            $output->writeLine('2. Encrypt values: php console.php secrets:encrypt "your-value"');
            $output->writeLine('3. Add encrypted values to .env.secrets');

            return ExitCode::SUCCESS;
        } catch (\Throwable $e) {
            $output->writeError('❌ Failed to create .env.secrets template: ' . $e->getMessage());

            return ExitCode::CANT_CREATE;
        }
    }

    #[ConsoleCommand('secrets:list', 'List all secret keys')]
    public function list(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        if ($this->secretManager === null) {
            $output->writeError('❌ SecretManager not available. Make sure ENCRYPTION_KEY is set in .env');

            return ExitCode::CONFIG_ERROR;
        }

        try {
            $secretKeys = $this->secretManager->getSecretKeys();

            if (empty($secretKeys)) {
                $output->writeInfo('ℹ️  No secret keys found');

                return ExitCode::SUCCESS;
            }

            $output->writeLine('🔐 Found secret keys:', ConsoleColor::CYAN);
            $output->newLine();

            foreach ($secretKeys as $key) {
                $output->writeLine("• {$key}", ConsoleColor::WHITE);
            }

            $output->newLine();
            $output->writeLine("Total: " . count($secretKeys) . " secrets", ConsoleColor::GRAY);

            return ExitCode::SUCCESS;
        } catch (\Throwable $e) {
            $output->writeError('❌ Failed to list secrets: ' . $e->getMessage());

            return ExitCode::CONFIG_ERROR;
        }
    }

    #[ConsoleCommand('secrets:validate', 'Validate secrets setup')]
    public function validate(ConsoleInput $input, ConsoleOutput $output): ExitCode
    {
        $basePath = getcwd();
        $encryptedLoader = new EncryptedEnvLoader($this->encryptionFactory, $this->randomGenerator);
        $env = Environment::fromFile($basePath . '/.env');
        $encryptionKey = $env->get('ENCRYPTION_KEY');

        $output->writeLine('🔍 Validating secrets setup...', ConsoleColor::CYAN);
        $output->newLine();

        $issues = $encryptedLoader->validateEncryptionSetup($basePath, $encryptionKey);

        if (empty($issues)) {
            $output->writeSuccess('✅ Secrets setup is valid!');

            if ($this->secretManager !== null) {
                $context = $this->secretManager->getSecurityContext();
                $output->newLine();
                $output->writeInfo('Security context:');
                $output->writeLine("• HTTPS: " . ($context->isHttps ? 'Yes' : 'No'));
                $output->writeLine("• Encryption: {$context->encryptionMethod}");
                $output->writeLine("• Server: {$context->serverName}");
                $output->writeLine("• Risk Level: {$context->getRiskLevel()->getDisplayName()}");
                $output->writeLine("• Summary: {$context->getSummary()}");
            }

            return ExitCode::SUCCESS;
        }

        $output->writeWarning('⚠️  Found issues with secrets setup:');
        $output->newLine();

        foreach ($issues as $issue) {
            $color = match ($issue['severity']) {
                'high' => ConsoleColor::RED,
                'medium' => ConsoleColor::YELLOW,
                default => ConsoleColor::WHITE
            };

            $output->writeLine("• {$issue['message']}", $color);
        }

        return ExitCode::CONFIG_ERROR;
    }
}
