<?php

/**
 * Хелпер для роботи з HTTP відповідями
 * Обгортка над Response класом
 *
 * @package Flowaxy\Support\Helpers
 * @version 1.0.0 Alpha prerelease
 */

declare(strict_types=1);

namespace Flowaxy\Support\Helpers;

use Flowaxy\Interface\Http\Response;

final class ResponseHelper
{
    /**
     * Відправити JSON відповідь
     *
     * @param mixed $data
     * @param int $statusCode
     * @return void
     */
    public static function json(mixed $data, int $statusCode = 200): void
    {
        Response::jsonResponse($data, $statusCode);
    }

    /**
     * Відправити успішну AJAX відповідь
     *
     * @param string|null $message Повідомлення
     * @param mixed $data Додаткові дані
     * @param int $statusCode HTTP статус код
     * @return void
     */
    public static function jsonSuccess(?string $message = null, mixed $data = null, int $statusCode = 200): void
    {
        $response = ['success' => true];

        if ($message !== null) {
            $response['message'] = $message;
        }

        if ($data !== null) {
            $response['data'] = $data;
        }

        Response::jsonResponse($response, $statusCode);
    }

    /**
     * Відправити помилкову AJAX відповідь
     *
     * @param string $error Повідомлення про помилку
     * @param mixed $data Додаткові дані
     * @param int $statusCode HTTP статус код
     * @return void
     */
    public static function jsonError(string $error, mixed $data = null, int $statusCode = 400): void
    {
        $response = [
            'success' => false,
            'error' => $error,
        ];

        if ($data !== null) {
            $response['data'] = $data;
        }

        Response::jsonResponse($response, $statusCode);
    }

    /**
     * Відправити XML відповідь
     *
     * @param array<string, mixed>|\SimpleXMLElement $data
     * @param int $statusCode
     * @param string $rootElement
     * @return void
     */
    public static function xml(array|\SimpleXMLElement $data, int $statusCode = 200, string $rootElement = 'root'): void
    {
        http_response_code($statusCode);
        header('Content-Type: application/xml; charset=UTF-8');

        if (is_array($data)) {
            echo XmlHelper::fromArray($data, $rootElement);
        } else {
            echo $data->asXML();
        }
    }

    /**
     * Відправити HTML відповідь
     *
     * @param string $html
     * @param int $statusCode
     * @return void
     */
    public static function html(string $html, int $statusCode = 200): void
    {
        http_response_code($statusCode);
        header('Content-Type: text/html; charset=UTF-8');
        echo $html;
    }

    /**
     * Відправити текст відповідь
     *
     * @param string $text
     * @param int $statusCode
     * @return void
     */
    public static function text(string $text, int $statusCode = 200): void
    {
        http_response_code($statusCode);
        header('Content-Type: text/plain; charset=UTF-8');
        echo $text;
    }

    /**
     * Виконати редірект
     *
     * @param string $url
     * @param int $statusCode
     * @return void
     */
    public static function redirect(string $url, int $statusCode = 302): void
    {
        Response::redirectStatic($url, $statusCode);
    }

    /**
     * Завантажити файл
     *
     * @param string $filePath
     * @param string|null $filename
     * @return void
     */
    public static function download(string $filePath, ?string $filename = null): void
    {
        if (!FileHelper::exists($filePath)) {
            http_response_code(404);
            return;
        }

        $filename = $filename ?? FileHelper::basename($filePath);
        $mimeType = FileHelper::mimeType($filePath) ?: 'application/octet-stream';

        header('Content-Type: ' . $mimeType);
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Content-Length: ' . FileHelper::size($filePath));

        readfile($filePath);
        exit;
    }

    /**
     * Відправити файл
     *
     * @param string $filePath
     * @param string|null $mimeType
     * @return void
     */
    public static function file(string $filePath, ?string $mimeType = null): void
    {
        if (!FileHelper::exists($filePath)) {
            http_response_code(404);
            return;
        }

        $mimeType = $mimeType ?? FileHelper::mimeType($filePath) ?: 'application/octet-stream';

        header('Content-Type: ' . $mimeType);
        header('Content-Length: ' . FileHelper::size($filePath));

        readfile($filePath);
        exit;
    }

    /**
     * Відправити потокову відповідь
     *
     * @param resource $stream
     * @param string|null $mimeType
     * @return void
     */
    public static function stream($stream, ?string $mimeType = null): void
    {
        if (!is_resource($stream)) {
            http_response_code(500);
            return;
        }

        if ($mimeType !== null) {
            header('Content-Type: ' . $mimeType);
        }

        // @phpstan-ignore-next-line - это функция fpassthru() для файловых потоков, а не системная команда passthru()
        fpassthru($stream);
        fclose($stream);
        exit;
    }

    /**
     * Встановити статус код
     *
     * @param int $statusCode
     * @return void
     */
    public static function status(int $statusCode): void
    {
        http_response_code($statusCode);
    }

    /**
     * Встановити заголовок
     *
     * @param string $name
     * @param string $value
     * @return void
     */
    public static function header(string $name, string $value): void
    {
        header("{$name}: {$value}");
    }

    /**
     * Встановити cookie
     *
     * @param string $name
     * @param string $value
     * @param int $expire
     * @param string $path
     * @param string $domain
     * @param bool $secure
     * @param bool $httpOnly
     * @return void
     */
    public static function cookie(string $name, string $value, int $expire = 0, string $path = '/', string $domain = '', bool $secure = false, bool $httpOnly = false): void
    {
        setcookie($name, $value, $expire, $path, $domain, $secure, $httpOnly);
    }

    /**
     * Додати дані до сесії для наступного запиту
     *
     * @param string $key
     * @param mixed $value
     * @return void
     */
    public static function with(string $key, mixed $value): void
    {
        if (class_exists(\Flowaxy\Support\Facades\SessionFacade::class)) {
            \Flowaxy\Support\Facades\SessionFacade::manager()->set($key, $value);
        }
    }

    /**
     * Повернутися назад
     *
     * @param int $statusCode
     * @return void
     */
    public static function back(int $statusCode = 302): void
    {
        $referer = $_SERVER['HTTP_REFERER'] ?? '/';
        self::redirect($referer, $statusCode);
    }

    /**
     * Відправити view
     *
     * @param string $view
     * @param array<string, mixed> $data
     * @param int $statusCode
     * @return void
     */
    public static function view(string $view, array $data = [], int $statusCode = 200): void
    {
        if (class_exists(\Flowaxy\Interface\UI\View::class)) {
            $viewInstance = new \Flowaxy\Interface\UI\View($view, $data);
            http_response_code($statusCode);
            echo $viewInstance->render();
        } else {
            self::html('View not found', 404);
        }
    }
}
