<?php

namespace apexl\Io\services;

use apexl\ClassEngine\EngineSingleton;
use apexl\Io\includes\Hook;
use apexl\Io\interfaces\messageInterface;
use Psr\Http\Message\ServerRequestInterface as Request;

/**
 * Class Messages
 * Class to provide a generalised store for communication - allows the addition to, and subtraction from the api response.
 * @package apexl\Io\includes
 */
class Output extends EngineSingleton implements messageInterface
{
    protected static $messages;
    protected static $metadata;
    protected static $response;
    protected static $systemErrors;

    public static function reset()
    {
        self::$response = null;
        self::$systemErrors = [];
        self::$messages = [];
        self::$metadata = [];
    }

    public static function addSystemError($e, $severity = "critical")
    {
        $message = [
            'status' => in_array($e->getCode(), [200, 301, 302, 400, 401, 403, 500]) ? $e->getCode() : 500,
            'message' => $e->getMessage(),
            'file' => $e->getFile(),
            'line' => $e->getLine(),
            'trace' => $e->getTrace(),
            'severity' => $severity,
        ];
        $message = Hook::processHook('addSystemError', $message, $e, $severity, self::getInstance());
        self::$systemErrors[] = $message;
    }

    public static function addMessage(
        string $name,
        string $type,
        string $content,
        string $icon = '',
        ?int $timeout = null,
        ?string $id = null
    ): void {
        $message = [
            'content' => $content,
            'type' => $type,
            'id' => $id ?? uniqid(),
            'icon' => $icon,
            'timeout' => $timeout,
        ];
        $message = Hook::processHook('addMessage', $message, $name, self::getInstance());
        self::$messages[$name] = $message;
    }

    public static function addRedirect(string $name, string $destination): void
    {
        self::addMetadata($name, 'redirect', $destination);
    }

    public static function addMetadata($name, $type, $contents)
    {
        $metadata = [$type => $contents];
        $metadata = Hook::processHook('addMetadata', $metadata, $name, self::getInstance());
        self::$metadata[$name] = $metadata;
    }

    /**
     * @param Request|null $request
     */
    public static function addResponse(Request $request = null, array $response = [], bool $success = true)
    {
        //Allows us to alter the response provided with a hook. We require the request to grab the current route.
        $path = pathUtility::getInstance();
        //allow us to inject data to the response object from elseware and maintain it (or override as appropriate)
        $response = array_merge((self::getResponse() ?? []), $response);
        $response['success'] = $success;
        self::$response = Hook::processHook(
            'addResponse',
            $response,
            ($request !== null ? $path->getRouteName($request) : null),
            self::getInstance()
        );
    }

    public static function getResponse()
    {
        return self::$response;
    }

    public static function getOutput()
    {
        $output = [];
        if (self::getSystemErrors()) {
            $output += ['systemErrors' => self::getSystemErrors()];
        }
        if (self::getResponse()) {
            $output += self::getResponse();
        }
        if (self::getMetadata()) {
            foreach (self::getMetadata() as $meta) {
                $output += $meta;
            }
        }
        if (self::getMessages()) {
            $output['messages'] = self::getMessages();
        }

        return $output ?? [];
    }

    public static function getSystemErrors()
    {
        return self::$systemErrors ?? false;
    }

    public static function getMetadata($name = null)
    {
        return self::$metadata[$name] ?? self::$metadata;
    }

    public static function getMessages($name = null)
    {
        return self::$messages[$name] ?? self::$messages;
    }
}
