<?php
declare(strict_types=1);

namespace App\Framework\ExceptionHandling;

use App\Framework\DI\Initializer;
use Fiber;

final class ErrorScope
{
    private array $stack = [];

    #[Initializer]
    public static function initialize(): ErrorScope
    {
        return new self;
    }

    public function enter(ErrorScopeContext $context): int
    {
        $id = $this->fiberId();
        $this->stack[$id] ??= [];
        $this->stack[$id][] = $context;
        return count($this->stack[$id]);
    }

    public function current(): ?ErrorScopeContext
    {
        $id = $this->fiberId();
        $stack = $this->stack[$id] ?? [];
        return end($stack) ?? null;
    }

    public function leave(int $token): void
    {
        $id = $this->fiberId();
        if(!isset($this->stack[$id])) {
            return;
        }
        while(!empty($this->stack[$id]) && count($this->stack[$id]) >= $token) {
            array_pop($this->stack[$id]);
        }
        if(empty($this->stack[$id])) {
            unset($this->stack[$id]);
        }
    }

    private function fiberId(): int
    {
        $fiber = Fiber::getCurrent();
        return $fiber ? spl_object_id($fiber) : 0;
    }
}
