<?php

declare(strict_types=1);

namespace App\Framework\Exception;

class FrameworkException extends \RuntimeException
{
    protected ExceptionContext $context;

    public function __construct(
        string $message,
        int $code = 0,
        ?\Throwable $previous = null,
        ?ExceptionContext $context = null
    ) {
        parent::__construct($message, $code, $previous);
        $this->context = $context ?? ExceptionContext::empty();
    }

    public function getContext(): ExceptionContext
    {
        return $this->context;
    }

    public function withContext(ExceptionContext $context): self
    {
        $new = clone $this;
        $new->context = $context;
        return $new;
    }

    public function withOperation(string $operation, ?string $component = null): self
    {
        return $this->withContext(
            $this->context->withOperation($operation, $component)
        );
    }

    public function withData(array $data): self
    {
        return $this->withContext(
            $this->context->withData($data)
        );
    }

    public function withDebug(array $debug): self
    {
        return $this->withContext(
            $this->context->withDebug($debug)
        );
    }

    public function withMetadata(array $metadata): self
    {
        return $this->withContext(
            $this->context->withMetadata($metadata)
        );
    }

    public function toArray(): array
    {
        return [
            'class' => static::class,
            'message' => $this->getMessage(),
            'code' => $this->getCode(),
            'file' => $this->getFile(),
            'line' => $this->getLine(),
            'context' => $this->context->toArray(),
            'trace' => $this->getTraceAsString(),
        ];
    }
}
