<?php

declare(strict_types=1);

namespace App\Framework\Database\Exception;

use App\Framework\Database\ValueObjects\SqlState;
use App\Framework\Exception\ErrorCode;
use App\Framework\Exception\ExceptionContext;
use App\Framework\Exception\ExceptionMetadata;
use App\Framework\Exception\FrameworkException;

class DatabaseException extends FrameworkException
{
    public function __construct(
        string $message,
        ExceptionContext $context,
        ErrorCode $errorCode,
        protected ?SqlState $sqlState = null,
        ?\Throwable $previous = null,
        int $httpStatusCode = 500,
        ?ExceptionMetadata $metadata = null
    ) {
        parent::__construct($message, $context, $httpStatusCode, $previous, $errorCode, $metadata);
    }

    /**
     * Create exception from context with optional SQLSTATE
     *
     * NOTE: SqlState is added as last parameter to maintain parent signature compatibility
     * Parent signature: fromContext(string, ExceptionContext, ?ErrorCode, ?\Throwable, int)
     */
    public static function fromContext(
        string $message,
        ExceptionContext $context,
        ?ErrorCode $errorCode = null,
        ?\Throwable $previous = null,
        int $httpStatusCode = 500,
        ?SqlState $sqlState = null
    ): static {
        return new static(
            message: $message,
            context: $context,
            errorCode: $errorCode ?? ErrorCode::INTERNAL,
            sqlState: $sqlState,
            previous: $previous,
            httpStatusCode: $httpStatusCode
        );
    }

    /**
     * Get the SQLSTATE associated with this exception
     */
    public function getSqlState(): ?SqlState
    {
        return $this->sqlState;
    }

    /**
     * Check if this exception has an associated SQLSTATE
     */
    public function hasSqlState(): bool
    {
        return $this->sqlState !== null;
    }

    /**
     * Override withMetadata to maintain DatabaseException structure
     */
    public function withMetadata(ExceptionMetadata $metadata): static
    {
        return new static(
            message: $this->getMessage(),
            context: $this->context,
            errorCode: $this->errorCode ?? ErrorCode::INTERNAL,
            sqlState: $this->sqlState,
            previous: $this->getPrevious(),
            httpStatusCode: $this->getCode(),
            metadata: $metadata
        );
    }
}
