<?php
/**
 * HTTP Response Handler
 *
 * @package Licenzo\Framework\Http
 */

namespace Licenzo\Framework\Http;

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

/**
 * Unified Response Handler for AJAX and REST API
 */
class Response {

    /**
     * Response data
     *
     * @var array
     */
    private $data = [];

    /**
     * Response status code
     *
     * @var int
     */
    private $statusCode = 200;

    /**
     * Response headers
     *
     * @var array
     */
    private $headers = [];

    /**
     * Response content
     *
     * @var string
     */
    private $content = '';

    /**
     * Header bag instance
     *
     * @var \Licenzo\Framework\Http\HeaderBag
     */
    private $headerBag;

    /**
     * Whether this is a success response
     *
     * @var bool
     */
    private $success = true;

    /**
     * Error message
     *
     * @var string|null
     */
    private $message = null;

    /**
     * Constructor
     *
     * @param mixed $data
     * @param int $statusCode
     * @param array $headers
     */
    public function __construct($data = [], $statusCode = 200, $headers = [])
    {
        $this->data = $data;
        $this->statusCode = $statusCode;
        $this->headers = $headers;
        $this->success = $statusCode >= 200 && $statusCode < 400;

        // Set content based on data
        if (is_string($data)) {
            $this->content = $data;
        } else {
            $this->content = json_encode($data);
        }
    }

    /**
     * Create a success response
     *
     * @param mixed $data
     * @param string|null $message
     * @param int $statusCode
     * @return static
     */
    public static function success($data = [], $message = null, $statusCode = 200) {
        $response = new static($data, $statusCode);
        $response->message = $message;
        $response->success = true;

        return $response;
    }

    /**
     * Create an error response
     *
     * @param string $message
     * @param mixed $data
     * @param int $statusCode
     * @return static
     */
    public static function error($message, $data = [], $statusCode = 400) {
        $response = new static($data, $statusCode);
        $response->message = $message;
        $response->success = false;

        return $response;
    }

    /**
     * Set response data
     *
     * @param mixed $data
     * @return $this
     */
    public function setData($data) {
        $this->data = $data;

        // Update content based on data
        if (is_string($data)) {
            $this->content = $data;
        } else {
            $this->content = json_encode($data);
        }

        return $this;
    }

    /**
     * Get response data
     *
     * @return mixed
     */
    public function getData() {
        return $this->data;
    }

    /**
     * Get response content
     *
     * @return string
     */
    public function getContent() {
        return $this->content;
    }

    /**
     * Set response content
     *
     * @param string $content
     * @return $this
     */
    public function setContent($content) {
        $this->content = $content;
        return $this;
    }

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

    /**
     * Get headers object (for compatibility with pipeline)
     *
     * @return \Licenzo\Framework\Http\HeaderBag
     */
    public function headers() {
        if (!isset($this->headerBag)) {
            $this->headerBag = new HeaderBag($this->headers);
        }
        return $this->headerBag;
    }

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

    /**
     * Set response message
     *
     * @param string $message
     * @return $this
     */
    public function setMessage($message) {
        $this->message = $message;
        return $this;
    }

    /**
     * Set status code
     *
     * @param int $statusCode
     * @return $this
     */
    public function setStatusCode($statusCode) {
        $this->statusCode = $statusCode;
        return $this;
    }

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

    /**
     * Add header (alias for addHeader)
     *
     * @param string $key
     * @param string $value
     * @return $this
     */
    public function header($key, $value) {
        return $this->addHeader($key, $value);
    }

    /**
     * Set multiple headers
     *
     * @param array $headers
     * @return $this
     */
    public function setHeaders(array $headers) {
        $this->headers = array_merge($this->headers, $headers);
        return $this;
    }

    /**
     * Send as WordPress AJAX response
     *
     * @return void
     */
    public function sendAjax() {
        // Set headers
        foreach ($this->headers as $key => $value) {
            header("{$key}: {$value}");
        }

        // Send the appropriate WordPress AJAX response
        if ($this->success) {
            wp_send_json_success($this->formatAjaxData(), $this->statusCode);
        } else {
            wp_send_json_error($this->formatAjaxData(), $this->statusCode);
        }
    }

    /**
     * Send as REST API response
     *
     * @return \WP_REST_Response
     */
    public function sendRest() {
        $response = new \WP_REST_Response($this->formatRestData(), $this->statusCode);

        // Add headers
        foreach ($this->headers as $key => $value) {
            $response->header($key, $value);
        }

        return $response;
    }

    /**
     * Get response as array (for manual handling)
     *
     * @return array
     */
    public function toArray() {
        return [
            'success' => $this->success,
            'data' => $this->data,
            'message' => $this->message,
            'status_code' => $this->statusCode,
            'headers' => $this->headers
        ];
    }

    /**
     * Format data for AJAX response
     *
     * @return array
     */
    private function formatAjaxData() {
        $response = [];

        // Add data
        if (!empty($this->data)) {
            if (is_array($this->data)) {
                $response = array_merge($response, $this->data);
            } else {
                $response['data'] = $this->data;
            }
        }

        // Add message if present
        if ($this->message !== null) {
            $response['message'] = $this->message;
        }

        // Add timestamp
        $response['timestamp'] = gmdate('Y-m-d H:i:s');

        return $response;
    }

    /**
     * Format data for REST API response
     *
     * @return array
     */
    private function formatRestData() {
        return [
            'success' => $this->success,
            'data' => $this->data,
            'message' => $this->message,
            'timestamp' => gmdate('Y-m-d H:i:s')
        ];
    }

    /**
     * Create a JSON response (for custom handling)
     *
     * @return string
     */
    public function toJson() {
        return json_encode($this->formatRestData());
    }

    /**
     * Magic method to convert to string
     *
     * @return string
     */
    public function __toString() {
        return $this->toJson();
    }

    /**
     * Common success responses
     */

    /**
     * Create a "created" success response
     *
     * @param mixed $data
     * @param string $message
     * @return static
     */
    public static function created($data = [], $message = 'Resource created successfully') {
        return static::success($data, $message, 201);
    }

    /**
     * Create a "no content" success response
     *
     * @param string $message
     * @return static
     */
    public static function noContent($message = 'Operation completed successfully') {
        return static::success([], $message, 204);
    }

    /**
     * Common error responses
     */

    /**
     * Create a "not found" error response
     *
     * @param string $message
     * @return static
     */
    public static function notFound($message = 'Resource not found') {
        return static::error($message, [], 404);
    }

    /**
     * Create an "unauthorized" error response
     *
     * @param string $message
     * @return static
     */
    public static function unauthorized($message = 'Unauthorized access') {
        return static::error($message, [], 401);
    }

    /**
     * Create a "forbidden" error response
     *
     * @param string $message
     * @return static
     */
    public static function forbidden($message = 'Access forbidden') {
        return static::error($message, [], 403);
    }

    /**
     * Create a "validation error" response
     *
     * @param array $errors
     * @param string $message
     * @return static
     */
    public static function validationError($errors = [], $message = 'Validation failed') {
        return static::error($message, ['errors' => $errors], 422);
    }

    /**
     * Create an "internal server error" response
     *
     * @param string $message
     * @param mixed $debug
     * @return static
     */
    public static function serverError($message = 'Internal server error', $debug = null) {
        $data = [];
        if ($debug !== null && defined('WP_DEBUG') && WP_DEBUG) {
            $data['debug'] = $debug;
        }

        return static::error($message, $data, 500);
    }
}
