<?php
/**
 * HTTP Exception
 *
 * @package Licenzo\Framework\Exceptions
 */

namespace Licenzo\Framework\Exceptions;

use Exception;

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * HTTP Exception for handling HTTP-related errors
 */
class HttpException extends Exception
{
    /**
     * HTTP status code
     *
     * @var int
     */
    protected $statusCode;

    /**
     * Additional data to include in response
     *
     * @var array
     */
    protected $data = [];

    /**
     * HTTP headers
     *
     * @var array
     */
    protected $headers = [];

    /**
     * Constructor
     *
     * @param int $statusCode HTTP status code
     * @param string $message Error message
     * @param array $data Additional data
     * @param array $headers HTTP headers
     * @param Exception|null $previous Previous exception
     */
    public function __construct(
        int $statusCode,
        string $message = '',
        array $data = [],
        array $headers = [],
        Exception $previous = null
    ) {
        $this->statusCode = $statusCode;
        $this->data = $data;
        $this->headers = $headers;

        // Use default message if none provided
        if (empty($message)) {
            $message = $this->getDefaultMessage($statusCode);
        }

        parent::__construct($message, $statusCode, $previous);
    }

    /**
     * Get HTTP status code
     *
     * @return int
     */
    public function getStatusCode(): int
    {
        return $this->statusCode;
    }

    /**
     * Get additional data
     *
     * @return array
     */
    public function getData(): array
    {
        return $this->data;
    }

    /**
     * Check if exception has additional data
     *
     * @return bool
     */
    public function hasData(): bool
    {
        return !empty($this->data);
    }

    /**
     * Get HTTP headers
     *
     * @return array
     */
    public function getHeaders(): array
    {
        return $this->headers;
    }

    /**
     * Set additional data
     *
     * @param array $data
     * @return $this
     */
    public function setData(array $data): self
    {
        $this->data = $data;
        return $this;
    }

    /**
     * Add data item
     *
     * @param string $key
     * @param mixed $value
     * @return $this
     */
    public function addData(string $key, $value): self
    {
        $this->data[$key] = $value;
        return $this;
    }

    /**
     * Set HTTP headers
     *
     * @param array $headers
     * @return $this
     */
    public function setHeaders(array $headers): self
    {
        $this->headers = $headers;
        return $this;
    }

    /**
     * Add HTTP header
     *
     * @param string $key
     * @param string $value
     * @return $this
     */
    public function addHeader(string $key, string $value): self
    {
        $this->headers[$key] = $value;
        return $this;
    }

    /**
     * Get default message for status code
     *
     * @param int $statusCode
     * @return string
     */
    protected function getDefaultMessage(int $statusCode): string
    {
        $messages = [
            400 => 'Bad Request',
            401 => 'Unauthorized',
            403 => 'Forbidden',
            404 => 'Not Found',
            405 => 'Method Not Allowed',
            409 => 'Conflict',
            422 => 'Unprocessable Entity',
            429 => 'Too Many Requests',
            500 => 'Internal Server Error',
            502 => 'Bad Gateway',
            503 => 'Service Unavailable',
            504 => 'Gateway Timeout',
        ];

        return $messages[$statusCode] ?? 'HTTP Error';
    }

    /**
     * Create a 400 Bad Request exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function badRequest(string $message = '', array $data = []): self
    {
        return new static(400, $message, $data);
    }

    /**
     * Create a 401 Unauthorized exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function unauthorized(string $message = '', array $data = []): self
    {
        return new static(401, $message, $data);
    }

    /**
     * Create a 403 Forbidden exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function forbidden(string $message = '', array $data = []): self
    {
        return new static(403, $message, $data);
    }

    /**
     * Create a 404 Not Found exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function notFound(string $message = '', array $data = []): self
    {
        return new static(404, $message, $data);
    }

    /**
     * Create a 405 Method Not Allowed exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function methodNotAllowed(string $message = '', array $data = []): self
    {
        return new static(405, $message, $data);
    }

    /**
     * Create a 409 Conflict exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function conflict(string $message = '', array $data = []): self
    {
        return new static(409, $message, $data);
    }

    /**
     * Create a 422 Unprocessable Entity exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function unprocessableEntity(string $message = '', array $data = []): self
    {
        return new static(422, $message, $data);
    }

    /**
     * Create a 429 Too Many Requests exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function tooManyRequests(string $message = '', array $data = []): self
    {
        return new static(429, $message, $data);
    }

    /**
     * Create a 500 Internal Server Error exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function internalServerError(string $message = '', array $data = []): self
    {
        return new static(500, $message, $data);
    }

    /**
     * Create a 502 Bad Gateway exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function badGateway(string $message = '', array $data = []): self
    {
        return new static(502, $message, $data);
    }

    /**
     * Create a 503 Service Unavailable exception
     *
     * @param string $message
     * @param array $data
     * @return static
     */
    public static function serviceUnavailable(string $message = '', array $data = []): self
    {
        return new static(503, $message, $data);
    }
}
