<?php
declare(strict_types=1);

namespace App\Framework\Context;

final readonly class ExecutionContext
{
    public function __construct(
        private ContextType $type,
        private array $metadata = []
    ) {}

    public function getType(): ContextType
    {
        return $this->type;
    }

    public function isWeb(): bool
    {
        return $this->type === ContextType::WEB;
    }

    public function isWorker(): bool
    {
        return $this->type === ContextType::WORKER;
    }

    public function isConsole(): bool
    {
        return $this->type === ContextType::CONSOLE;
    }

    public function isCli(): bool
    {
        return in_array($this->type, [
            ContextType::CONSOLE,
            ContextType::WORKER,
            ContextType::CLI_SCRIPT
        ]);
    }

    public function isTest(): bool
    {
        return $this->type === ContextType::TEST;
    }

    public function getMetadata(): array
    {
        return array_merge([
            'type' => $this->type->value,
            'sapi' => php_sapi_name(),
            'script' => $_SERVER['argv'][0] ?? null,
            'command_line' => implode(' ', $_SERVER['argv'] ?? []),
            'pid' => getmypid(),
        ], $this->metadata);
    }

    public static function detect(): self
    {
        // Test Environment
        if (defined('PHPUNIT_COMPOSER_INSTALL') ||
            isset($_ENV['APP_ENV']) && $_ENV['APP_ENV'] === 'testing') {
            return new self(ContextType::TEST, ['detected_by' => 'phpunit_or_env']);
        }

        // Web Request
        if (php_sapi_name() !== 'cli') {
            return new self(ContextType::WEB, ['detected_by' => 'sapi']);
        }

        // CLI Detection
        $scriptName = $_SERVER['argv'][0] ?? '';
        $commandLine = implode(' ', $_SERVER['argv'] ?? []);

        $type = match(true) {
            str_contains($scriptName, 'worker') => ContextType::WORKER,
            str_contains($scriptName, 'artisan') => ContextType::CONSOLE,
            str_contains($commandLine, 'pest') => ContextType::TEST,
            str_contains($commandLine, 'phpunit') => ContextType::TEST,
            default => ContextType::CLI_SCRIPT
        };

        return new self($type, [
            'detected_by' => 'cli_analysis',
            'script_name' => $scriptName,
            'command_line' => $commandLine
        ]);
    }

    public static function forWorker(): self
    {
        return new self(ContextType::WORKER, ['forced_by' => 'worker']);
    }

    public static function forTest(): self
    {
        return new self(ContextType::TEST, ['forced_by' => 'test']);
    }

    public static function forConsole(): self
    {
        return new self(ContextType::CONSOLE, ['forced_by' => 'console']);
    }

    public static function forWeb(): self
    {
        return new self(ContextType::WEB, ['forced_by' => 'web']);
    }
}
