<?php

declare(strict_types=1);

namespace App\Framework\Logging\Commands;

use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ConsoleInput;
use App\Framework\Console\ExitCode;
use App\Framework\Core\ValueObjects\Byte;

/**
 * Console Command zur Überwachung der Log-Infrastruktur
 *
 * Prüft:
 * - Log-Verzeichnisse und Berechtigungen
 * - Log-Dateien und deren Größen
 * - Rotierte Log-Dateien
 * - Disk-Space-Verfügbarkeit
 * - Schreibrechte
 *
 * Usage:
 * ```bash
 * php console.php log:health-check
 * php console.php log:health-check --detailed
 * php console.php log:health-check --fix-permissions
 * ```
 */
final readonly class LogHealthCheckCommand
{
    #[ConsoleCommand(name: 'logs:health-check', description: 'Check log infrastructure health and identify issues')]
    public function execute(ConsoleInput $input): ExitCode
    {
        $detailed = $input->hasOption('detailed');
        $fixPermissions = $input->hasOption('fix-permissions');

        $basePath = getcwd() ?: '/var/www/html';
        $logsPath = $basePath . '/storage/logs';

        echo "═══════════════════════════════════════════════════\n";
        echo "           Log Infrastructure Health Check          \n";
        echo "═══════════════════════════════════════════════════\n\n";

        $checks = [
            'directories' => $this->checkDirectories($logsPath, $basePath, $fixPermissions),
            'permissions' => $this->checkPermissions($logsPath, $basePath, $fixPermissions),
            'disk_space' => $this->checkDiskSpace($logsPath, $basePath),
            'log_files' => $this->checkLogFiles($logsPath, $basePath, $detailed),
        ];

        // Summary
        echo "\n═══════════════════════════════════════════════════\n";
        echo "                     Summary                        \n";
        echo "═══════════════════════════════════════════════════\n";

        $allPassed = true;
        foreach ($checks as $checkName => $passed) {
            $status = $passed ? '✓ PASS' : '✗ FAIL';
            $color = $passed ? "\033[32m" : "\033[31m";
            echo $color . $status . "\033[0m " . str_pad(ucfirst(str_replace('_', ' ', $checkName)), 30) . "\n";

            if (!$passed) {
                $allPassed = false;
            }
        }

        echo "\n";

        if ($allPassed) {
            echo "\033[32m✓ All checks passed! Log infrastructure is healthy.\033[0m\n";
            return ExitCode::SUCCESS;
        }

        echo "\033[31m✗ Some checks failed. Please review above output.\033[0m\n";

        if (!$fixPermissions) {
            echo "\033[33mTip: Use --fix-permissions to automatically fix permission issues.\033[0m\n";
        }

        return ExitCode::GENERAL_ERROR;
    }

    /**
     * Prüft ob Log-Verzeichnisse existieren
     */
    private function checkDirectories(string $logsPath, string $basePath, bool $fix): bool
    {
        echo "📁 Checking log directories...\n";

        $directories = [
            $logsPath,
            $logsPath . '/app',
            $logsPath . '/debug',
            $logsPath . '/security',
        ];

        $allExist = true;

        foreach ($directories as $dir) {
            $exists = is_dir($dir);

            if ($exists) {
                echo "  ✓ " . $this->relativePath($dir, $basePath) . "\n";
            } else {
                echo "  ✗ " . $this->relativePath($dir, $basePath) . " (missing)\n";
                $allExist = false;

                if ($fix) {
                    echo "    → Creating directory...\n";
                    mkdir($dir, 0777, true);
                    echo "    ✓ Directory created\n";
                    $allExist = true;
                }
            }
        }

        echo "\n";

        return $allExist;
    }

    /**
     * Prüft Schreibberechtigungen
     */
    private function checkPermissions(string $logsPath, string $basePath, bool $fix): bool
    {
        echo "🔐 Checking write permissions...\n";

        $testFile = $logsPath . '/.health-check-' . uniqid() . '.tmp';

        try {
            // Versuche Test-Datei zu schreiben
            $result = @file_put_contents($testFile, 'health check test');

            if ($result === false) {
                echo "  ✗ Cannot write to " . $this->relativePath($logsPath, $basePath) . "\n";

                if ($fix) {
                    echo "    → Attempting to fix permissions...\n";
                    @chmod($logsPath, 0777);
                    @chmod(dirname($logsPath), 0777);

                    // Retry
                    $result = @file_put_contents($testFile, 'health check test');

                    if ($result !== false) {
                        echo "    ✓ Permissions fixed\n";
                        @unlink($testFile);
                        echo "\n";
                        return true;
                    }
                }

                echo "\n";
                return false;
            }

            // Cleanup
            @unlink($testFile);

            $perms = substr(sprintf('%o', fileperms($logsPath)), -4);
            echo "  ✓ Write permissions OK (permissions: " . $perms . ")\n";
            echo "\n";

            return true;
        } catch (\Throwable $e) {
            echo "  ✗ Permission check failed: " . $e->getMessage() . "\n";
            echo "\n";
            return false;
        }
    }

    /**
     * Prüft verfügbaren Disk-Space
     */
    private function checkDiskSpace(string $logsPath, string $basePath): bool
    {
        echo "💾 Checking disk space...\n";

        $freeSpace = disk_free_space($logsPath);
        $totalSpace = disk_total_space($logsPath);

        if ($freeSpace === false || $totalSpace === false) {
            echo "  ✗ Could not determine disk space\n";
            echo "\n";
            return false;
        }

        $freeBytes = Byte::fromBytes((int) $freeSpace);
        $totalBytes = Byte::fromBytes((int) $totalSpace);
        $usedBytes = Byte::fromBytes((int) ($totalSpace - $freeSpace));

        $percentUsed = ($totalSpace > 0) ? round(($totalSpace - $freeSpace) / $totalSpace * 100, 2) : 0;

        echo "  Total:  " . $totalBytes->toHumanReadable() . "\n";
        echo "  Used:   " . $usedBytes->toHumanReadable() . " (" . $percentUsed . "%)\n";
        echo "  Free:   " . $freeBytes->toHumanReadable() . "\n";

        // Warn if less than 100MB free or more than 90% used
        if ($freeSpace < 100 * 1024 * 1024 || $percentUsed > 90) {
            echo "  \033[33m⚠ Warning: Low disk space!\033[0m\n";
            echo "\n";
            return false;
        }

        echo "  ✓ Disk space OK\n";
        echo "\n";

        return true;
    }

    /**
     * Prüft Log-Dateien
     */
    private function checkLogFiles(string $logsPath, string $basePath, bool $detailed): bool
    {
        echo "📄 Checking log files...\n";

        $logFiles = $this->findLogFiles($logsPath);

        if (empty($logFiles)) {
            echo "  ℹ No log files found (this is OK for a fresh install)\n";
            echo "\n";
            return true;
        }

        echo "  Found " . count($logFiles) . " log file(s)\n\n";

        $totalSize = 0;
        $warnings = [];

        foreach ($logFiles as $logFile) {
            $size = filesize($logFile);
            $totalSize += $size;

            $sizeBytes = Byte::fromBytes($size);
            $modified = date('Y-m-d H:i:s', filemtime($logFile));

            if ($detailed) {
                echo "  " . $this->relativePath($logFile, $basePath) . "\n";
                echo "    Size:     " . $sizeBytes->toHumanReadable() . "\n";
                echo "    Modified: " . $modified . "\n";

                // Check if file is very large
                if ($size > 50 * 1024 * 1024) { // 50MB
                    echo "    \033[33m⚠ Large file (consider rotation)\033[0m\n";
                    $warnings[] = $logFile;
                }

                echo "\n";
            }
        }

        $totalBytes = Byte::fromBytes($totalSize);
        echo "  Total log size: " . $totalBytes->toHumanReadable() . "\n";

        if (!empty($warnings)) {
            echo "\n  \033[33m⚠ " . count($warnings) . " file(s) exceed 50MB\033[0m\n";
        }

        echo "\n";

        return empty($warnings);
    }

    /**
     * Findet alle Log-Dateien rekursiv
     */
    private function findLogFiles(string $directory): array
    {
        $files = [];

        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($directory, \FilesystemIterator::SKIP_DOTS),
            \RecursiveIteratorIterator::SELF_FIRST
        );

        foreach ($iterator as $file) {
            if ($file->isFile() && preg_match('/\.(log|log\.\d+|log\.\d+\.gz)$/', $file->getFilename())) {
                $files[] = $file->getPathname();
            }
        }

        return $files;
    }

    /**
     * Gibt relativen Pfad zurück
     */
    private function relativePath(string $path, string $basePath): string
    {
        return str_replace($basePath . '/', '', $path);
    }
}
