<?php

namespace idoit\Module\JDisc\Helper;

// example:
// $sse = SSEMessenger::getInstance(1024); // Initialize with pad size
// $sse->sendLogMessage('Processing Data...');
// $sse->sendProgress(1, 50, 100, 'Halfway there!');
// $sse->sendEndMessage();

/**
 * Singleton class to help with sending Server-Sent Events (SSE) messages
 * with optional padding.
 */
class SSEMessenger
{
    private static ?SSEMessenger $instance = null;
    private ?int $padSize;

    /**
     * SSEMessenger constructor.
     *
     * @param int|null $padSize
     */
    private function __construct(?int $padSize)
    {
        $this->padSize = $padSize ?? (int) ini_get('output_buffering');
    }

    /**
     * Get the singleton instance of SSEMessenger.
     *
     * @param int|null $padSize
     * @return SSEMessenger
     */
    public static function getInstance(?int $padSize = null): SSEMessenger
    {
        if (self::$instance === null) {
            self::$instance = new SSEMessenger($padSize);
        }
        return self::$instance;
    }

    /**
     * Send a log message.
     *
     * @param string $message
     * @return void
     */
    public function sendLogMessage(string $message): void
    {
        $logMessage = json_encode([
            'type' => 'log',
            'message' => $message,
        ]);
        $this->sendData($logMessage);
    }

    /**
     * Send an end message.
     *
     * @param string|null $message
     * @return void
     */
    public function sendEndMessage(?string $message = null): void
    {
        $endMessage = [
            'type' => 'end',
        ];
        if ($message) {
            $endMessage['message'] = $message;
        }
        $endMessage = json_encode($endMessage);
        $this->sendData($endMessage);
    }

    /**
     * Send a progress message.
     *
     * @param int $id
     * @param int $step
     * @param int $max
     * @param string $message
     * @return void
     */
    public function sendProgressMessage(int $id, int $step, int $max, string $message): void
    {
        $progressMessage = json_encode([
            'type' => 'progress',
            'id' => $id,
            'progress' => $step / $max * 100,
            'message' => $message,
        ]);
        $this->sendData($progressMessage);
    }

    /**
     * Send an error message
     *
     * @param string $message
     * @return void
     */
    public function sendErrorMessage(string $message): void
    {
        $errorMessage = json_encode([
            'type' => 'error',
            'message' => $message,
        ]);
        $this->sendData($errorMessage);
    }

    /**
     * Send continue message
     *
     * @return void
     */
    public function sendContinueMessage(): void
    {
        $continueMessage = json_encode([
            'type' => 'continue',
        ]);
        $this->sendData($continueMessage);
    }

    /**
     * Send pause message
     *
     * @param int $time
     * @param string $actionMessage
     * @return void
     */
    public function sendPauseMessage(int $time, string $actionMessage): void
    {
        $pauseMessage = json_encode([
            'type' => 'pause',
            'time' => $time,
            'actionMessage' => $actionMessage,
        ]);
        $this->sendData($pauseMessage);
    }

    /**
     * Send data with padding if padSize is set.
     *
     * @param string $data
     * @return void
     */
    public function sendData(string $data): void
    {
        if ($this->padSize) {
            echo str_pad("data: $data", $this->padSize) . "\n\n";
        } else {
            echo "data: $data\n\n";
        }
        ob_flush();
        flush();
    }
}
