<?php

declare(strict_types=1);

namespace App\Framework\Telemetry;

use App\Framework\Telemetry\ValueObjects\Operation;

/**
 * Manages the telemetry context, including active operations and their relationships
 */
final class TelemetryContext
{
    /**
     * @var array<string, Operation> Map of operation IDs to Operation objects
     */
    private array $operations = [];

    /**
     * @var string|null ID of the current operation
     */
    private ?string $currentOperationId = null;

    /**
     * Get the ID of the current operation
     */
    public function getCurrentOperationId(): ?string
    {
        return $this->currentOperationId;
    }

    /**
     * Get the current operation
     */
    public function getCurrentOperation(): ?Operation
    {
        if ($this->currentOperationId === null) {
            return null;
        }

        return $this->operations[$this->currentOperationId] ?? null;
    }

    /**
     * Set the current operation
     */
    public function setCurrentOperation(Operation $operation): void
    {
        $this->operations[$operation->id] = $operation;
        $this->currentOperationId = $operation->id;
    }

    /**
     * Get an operation by ID
     */
    public function getOperation(string $id): ?Operation
    {
        return $this->operations[$id] ?? null;
    }

    /**
     * Remove an operation from the context
     */
    public function removeOperation(string $id): void
    {
        unset($this->operations[$id]);

        // If this was the current operation, clear the current operation ID
        if ($this->currentOperationId === $id) {
            $this->currentOperationId = null;
        }
    }

    /**
     * Restore the parent operation as the current operation
     */
    public function restoreParentOperation(?string $parentId): void
    {
        if ($parentId !== null && isset($this->operations[$parentId])) {
            $this->currentOperationId = $parentId;
        } else {
            $this->currentOperationId = null;
        }
    }

    /**
     * Get all active operations
     *
     * @return array<string, Operation>
     */
    public function getActiveOperations(): array
    {
        return array_filter($this->operations, fn (Operation $op) => ! $op->isCompleted());
    }

    /**
     * Get all operations
     *
     * @return array<string, Operation>
     */
    public function getAllOperations(): array
    {
        return $this->operations;
    }

    /**
     * Clear all operations
     */
    public function clear(): void
    {
        $this->operations = [];
        $this->currentOperationId = null;
    }

    /**
     * Get the operation stack as a string for debugging
     */
    public function getOperationStackAsString(): string
    {
        if ($this->currentOperationId === null) {
            return 'No active operations';
        }

        $stack = [];
        $currentId = $this->currentOperationId;

        while ($currentId !== null) {
            $operation = $this->operations[$currentId] ?? null;
            if ($operation === null) {
                break;
            }

            $stack[] = "{$operation->name} ({$operation->type})";
            $currentId = $operation->parentId;
        }

        return implode(' > ', array_reverse($stack));
    }
}
