<?php

declare(strict_types=1);

namespace App\Framework\Process\Console;

use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ExitCode;
use App\Framework\Process\Services\NpmService;

/**
 * NPM Console Commands.
 */
final readonly class NpmCommands
{
    public function __construct(
        private NpmService $npmService
    ) {
    }

    #[ConsoleCommand(name: 'npm:audit', description: 'Run NPM security audit')]
    public function audit(ConsoleInput $input): int
    {
        echo "Running NPM security audit...\n\n";

        $result = $this->npmService->audit();

        echo "🔒 Security Audit Results:\n\n";
        echo "  Total Vulnerabilities: {$result->total}\n\n";

        if ($result->hasVulnerabilities()) {
            echo "  📊 Breakdown by Severity:\n";
            echo "     Info:     {$result->info}\n";
            echo "     Low:      {$result->low}\n";
            echo "     Moderate: {$result->moderate}\n";
            echo "     High:     {$result->high}\n";
            echo "     Critical: {$result->critical}\n\n";

            if (! empty($result->vulnerabilities)) {
                echo "  📦 Affected Packages:\n";
                foreach ($result->vulnerabilities as $package) {
                    echo "     - {$package}\n";
                }
                echo "\n";
            }

            if ($result->hasCriticalIssues()) {
                echo "  ⚠️  CRITICAL: High or critical vulnerabilities found!\n";
                echo "     Run 'npm audit fix' to attempt automatic fixes.\n";

                return ExitCode::FAILURE;
            }

            echo "  ℹ️  Run 'npm audit fix' to attempt automatic fixes.\n";

            return ExitCode::WARNING;
        }

        echo "  ✅ No vulnerabilities found!\n";

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand(name: 'npm:audit-fix', description: 'Fix NPM security vulnerabilities')]
    public function auditFix(ConsoleInput $input): int
    {
        $force = $input->hasOption('force');

        echo "Attempting to fix security vulnerabilities" . ($force ? ' (--force)' : '') . "...\n\n";

        $success = $this->npmService->auditFix($force);

        if ($success) {
            echo "✅ Audit fix completed!\n";
            echo "   Run 'npm audit' to verify remaining vulnerabilities.\n";

            return ExitCode::SUCCESS;
        }

        echo "❌ Audit fix failed.\n";

        return ExitCode::FAILURE;
    }

    #[ConsoleCommand(name: 'npm:outdated', description: 'List outdated NPM packages')]
    public function outdated(ConsoleInput $input): int
    {
        echo "Checking for outdated packages...\n\n";

        $packages = $this->npmService->getOutdatedPackages();

        if (empty($packages)) {
            echo "✅ All packages are up to date!\n";

            return ExitCode::SUCCESS;
        }

        echo "📦 Found " . count($packages) . " outdated package(s):\n\n";

        foreach ($packages as $package) {
            echo "  📌 {$package->name}";

            if ($package->type !== null) {
                echo " ({$package->type})";
            }

            echo "\n";
            echo "     Current: {$package->currentVersion}\n";

            if ($package->wantedVersion !== null) {
                echo "     Wanted:  {$package->wantedVersion}\n";
            }

            if ($package->latestVersion !== null) {
                echo "     Latest:  {$package->latestVersion}\n";
            }

            echo "\n";
        }

        echo "  ℹ️  Run 'npm update' to update packages.\n";

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand(name: 'npm:installed', description: 'List installed NPM packages')]
    public function installed(ConsoleInput $input): int
    {
        echo "Loading installed packages...\n\n";

        $packages = $this->npmService->getInstalledPackages();

        if (empty($packages)) {
            echo "No packages installed.\n";

            return ExitCode::SUCCESS;
        }

        $dependencies = array_filter($packages, fn ($p) => $p->type === 'dependencies');
        $devDependencies = array_filter($packages, fn ($p) => $p->type === 'devDependencies');

        if (! empty($dependencies)) {
            echo "📦 Dependencies (" . count($dependencies) . "):\n";
            foreach ($dependencies as $package) {
                echo "   {$package->name}@{$package->currentVersion}\n";
            }
            echo "\n";
        }

        if (! empty($devDependencies)) {
            echo "🔧 DevDependencies (" . count($devDependencies) . "):\n";
            foreach ($devDependencies as $package) {
                echo "   {$package->name}@{$package->currentVersion}\n";
            }
            echo "\n";
        }

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand(name: 'npm:validate', description: 'Validate package.json')]
    public function validate(ConsoleInput $input): int
    {
        echo "Validating package.json...\n\n";

        $isValid = $this->npmService->validate();

        if ($isValid) {
            echo "✅ package.json is valid!\n";

            return ExitCode::SUCCESS;
        }

        echo "❌ package.json validation failed or not found!\n";

        return ExitCode::FAILURE;
    }

    #[ConsoleCommand(name: 'npm:version', description: 'Show NPM version')]
    public function version(ConsoleInput $input): int
    {
        $version = $this->npmService->getVersion();

        echo "NPM version: {$version}\n";

        return ExitCode::SUCCESS;
    }

    #[ConsoleCommand(name: 'npm:install', description: 'Install NPM dependencies')]
    public function install(ConsoleInput $input): int
    {
        $production = $input->hasOption('production') || $input->hasOption('prod');

        echo "Installing NPM dependencies" . ($production ? ' (production only)' : '') . "...\n\n";

        $success = $this->npmService->install($production);

        if ($success) {
            echo "✅ Dependencies installed successfully!\n";

            return ExitCode::SUCCESS;
        }

        echo "❌ Installation failed.\n";

        return ExitCode::FAILURE;
    }

    #[ConsoleCommand(name: 'npm:update', description: 'Update NPM dependencies')]
    public function update(ConsoleInput $input): int
    {
        $production = $input->hasOption('production') || $input->hasOption('prod');

        echo "Updating NPM dependencies" . ($production ? ' (production only)' : '') . "...\n\n";

        $success = $this->npmService->update($production);

        if ($success) {
            echo "✅ Dependencies updated successfully!\n";

            return ExitCode::SUCCESS;
        }

        echo "❌ Update failed.\n";

        return ExitCode::FAILURE;
    }

    #[ConsoleCommand(name: 'npm:clean', description: 'Clean node_modules and package-lock.json')]
    public function clean(ConsoleInput $input): int
    {
        echo "Cleaning node_modules and package-lock.json...\n\n";

        $success = $this->npmService->clean();

        if ($success) {
            echo "✅ Cleaned successfully!\n";
            echo "   Run 'npm install' to reinstall dependencies.\n";

            return ExitCode::SUCCESS;
        }

        echo "❌ Clean failed.\n";

        return ExitCode::FAILURE;
    }

    #[ConsoleCommand(name: 'npm:run', description: 'Run NPM script')]
    public function run(ConsoleInput $input): int
    {
        $script = $input->getArgument('script');

        if ($script === null) {
            echo "❌ Please provide a script name.\n";
            echo "Usage: php console.php npm:run <script>\n";

            return ExitCode::FAILURE;
        }

        echo "Running NPM script: {$script}...\n\n";

        $success = $this->npmService->runScript($script);

        if ($success) {
            echo "\n✅ Script completed successfully!\n";

            return ExitCode::SUCCESS;
        }

        echo "\n❌ Script failed.\n";

        return ExitCode::FAILURE;
    }
}
