<?php

declare(strict_types=1);

namespace App\Framework\ErrorHandling;

use App\Framework\Console\ConsoleColor;
use App\Framework\Console\ConsoleOutput;

/**
 * CLI-spezifischer Error Handler für Worker und Console
 */
final readonly class CliErrorHandler
{
    public function __construct(
        private ?ConsoleOutput $output = null
    ) {}

    public function register(): void
    {
        set_error_handler([$this, 'handleError']);
        set_exception_handler([$this, 'handleException']);
        register_shutdown_function([$this, 'handleShutdown']);
    }

    public function handleError(int $severity, string $message, string $file, int $line): bool
    {
        if (!(error_reporting() & $severity)) {
            return false;
        }

        $errorType = $this->getErrorType($severity);
        $color = $this->getErrorColor($severity);

        $output = $this->output ?? new ConsoleOutput();
        $output->writeLine("[$errorType] $message", $color);
        $output->writeLine("  in $file:$line", ConsoleColor::GRAY);

        if (in_array($severity, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR])) {
            exit(1);
        }

        return true;
    }

    public function handleException(\Throwable $exception): void
    {
        $output = $this->output ?? new ConsoleOutput();

        $output->writeLine("❌ Uncaught " . get_class($exception) . ": " . $exception->getMessage(), ConsoleColor::BRIGHT_RED);
        $output->writeLine("   File: " . $exception->getFile() . ":" . $exception->getLine(), ConsoleColor::RED);

        if ($exception->getPrevious()) {
            $output->writeLine("   Caused by: " . $exception->getPrevious()->getMessage(), ConsoleColor::YELLOW);
        }

        $output->writeLine("   Stack trace:", ConsoleColor::GRAY);
        foreach (explode("\n", $exception->getTraceAsString()) as $line) {
            $output->writeLine("     " . $line, ConsoleColor::GRAY);
        }

        exit(1);
    }

    public function handleShutdown(): void
    {
        $error = error_get_last();

        if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
            $output = $this->output ?? new ConsoleOutput();
            $output->writeLine("💥 Fatal Error: " . $error['message'], ConsoleColor::BRIGHT_RED);
            $output->writeLine("   File: " . $error['file'] . ":" . $error['line'], ConsoleColor::RED);
        }
    }

    private function getErrorType(int $severity): string
    {
        return match ($severity) {
            E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR => 'ERROR',
            E_WARNING, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING => 'WARNING',
            E_NOTICE, E_USER_NOTICE => 'NOTICE',
            E_STRICT => 'STRICT',
            E_RECOVERABLE_ERROR => 'RECOVERABLE_ERROR',
            E_DEPRECATED, E_USER_DEPRECATED => 'DEPRECATED',
            default => 'UNKNOWN'
        };
    }

    private function getErrorColor(int $severity): ConsoleColor
    {
        return match ($severity) {
            E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR => ConsoleColor::BRIGHT_RED,
            E_WARNING, E_CORE_WARNING, E_COMPILE_WARNING, E_USER_WARNING => ConsoleColor::YELLOW,
            E_NOTICE, E_USER_NOTICE => ConsoleColor::CYAN,
            E_DEPRECATED, E_USER_DEPRECATED => ConsoleColor::MAGENTA,
            default => ConsoleColor::WHITE
        };
    }
}
