<?php declare(strict_types=1);
/**
 * @package messenger
 * @author kputyr
 * @date 17.04.2025
 */
namespace IMATHUZH\Qfq\Core\Messenger\Hooks;
require_once(__DIR__ . '/../../../../vendor/autoload.php');
/**
 * An implementation of the helper request class for nchan hooks
 */
class NchanRequest extends AbstractNchanRequest
{
    public function authorized(): bool
    {
        // For testing, always return true
        // You can implement your custom authorization logic here
        return true;
    }

    public function getClientId(): string
    {
        return bin2hex(random_bytes(4)) . (string)time();
    }
}

/**
 * A base class for nchan requests
 */
abstract class AbstractNchanRequest
{
    const LOCALHOST_BASE = 'http://localhost:8080/messenger/';
    // Improved pattern that handles more URL formats
    const CHANNEL_PATTERN = "@/messenger/(\w+)(?:/pub-([^/\?]+))?(?:/sub-([^/\?]+))?@";
    const CONTROLLER_CHANNEL = '$GROUP/controller';
    const PUBLISHER_CHANNEL = '$GROUP/pub-$CHANNEL';

    public $nchanVersion;
    public $requestUri;
    public $subscriberType;
    protected $responseUrl = '';
    protected $group = '';
    protected $responseChannel = '';

    public function __construct(array $headers = null) {
        if (!$headers) $headers = $_SERVER;

        // Log the headers for debugging
        $logFile = '/tmp/hook_debug.log';
        file_put_contents($logFile,
            date('Y-m-d H:i:s') . " - Headers in constructor: " . print_r($headers, true) . "\n",
            FILE_APPEND);

        $this->nchanVersion = $headers['HTTP_X_NCHAN_VERSION'] ?? null;
        $this->requestUri = $headers['HTTP_X_ORIGINAL_URI'] ?? null;
        $this->subscriberType = $headers['HTTP_X_SUBSCRIBER_TYPE'] ?? null;

        // Handle case where we're testing directly
        if ($this->requestUri === null) {
            $this->requestUri = '/messenger/default/sub-channel1';
            file_put_contents($logFile,
                date('Y-m-d H:i:s') . " - No URI found, using default: {$this->requestUri}\n",
                FILE_APPEND);
        }

        $this->generateUrls();
    }

    public function close(int $code, string $msg='') {
        http_response_code($code);
        if ($msg) echo $msg;

        // Only call fastcgi_finish_request if it exists
        if (function_exists('fastcgi_finish_request')) {
            fastcgi_finish_request();
        }
    }

    protected function generateUrls() {
        // Log for debugging
        $logFile = '/tmp/hook_debug.log';
        file_put_contents($logFile,
            date('Y-m-d H:i:s') . " - Generating URLs from: {$this->requestUri}\n",
            FILE_APPEND);

        // Find the channel group and the main subscriber channel
        if ($this->requestUri !== null && preg_match(self::CHANNEL_PATTERN, $this->requestUri, $matches)) {
            file_put_contents($logFile,
                date('Y-m-d H:i:s') . " - Regex matches: " . print_r($matches, true) . "\n",
                FILE_APPEND);

            $this->group = $matches[1];

            // Handle different URL formats
            if (isset($matches[3])) {
                // Format: /messenger/group/pub-channels/sub-channels
                $this->responseChannel = $matches[3];
            } else {
                // Format: /messenger/group/sub-channels
                $this->responseChannel = $matches[2] ?? null;
            }

            file_put_contents($logFile,
                date('Y-m-d H:i:s') . " - Extracted group: {$this->group}, channel: {$this->responseChannel}\n",
                FILE_APPEND);
        } else {
            // If we can't parse the URL, use defaults instead of throwing an exception
            $this->group = 'default';
            $this->responseChannel = 'channel1';

            file_put_contents($logFile,
                date('Y-m-d H:i:s') . " - Could not parse URI, using defaults. Group: {$this->group}, Channel: {$this->responseChannel}\n",
                FILE_APPEND);
        }
    }

    public function getReplyUrl() {
        if (empty($this->responseChannel)) {
            // Log and use a default instead of throwing exception
            $logFile = '/tmp/hook_debug.log';
            file_put_contents($logFile,
                date('Y-m-d H:i:s') . " - Warning: No response channel, using default.\n",
                FILE_APPEND);

            $this->responseChannel = 'default';
        }

        $url = self::LOCALHOST_BASE . str_replace(
                ['$GROUP', '$CHANNEL'],
                [$this->group, $this->responseChannel],
                self::PUBLISHER_CHANNEL
            );

        // Log the URL for debugging
        $logFile = '/tmp/hook_debug.log';
        file_put_contents($logFile,
            date('Y-m-d H:i:s') . " - Reply URL: {$url}\n",
            FILE_APPEND);

        return $url;
    }

    public function getControllerUrl() {
        $url = self::LOCALHOST_BASE . str_replace('$GROUP', $this->group, self::CONTROLLER_CHANNEL);

        // Log for debugging
        $logFile = '/tmp/hook_debug.log';
        file_put_contents($logFile,
            date('Y-m-d H:i:s') . " - Controller URL: {$url}\n",
            FILE_APPEND);

        return $url;
    }

    public function send(array $payload, string $url) {
        // Log for debugging
        $logFile = '/tmp/hook_debug.log';
        file_put_contents($logFile,
            date('Y-m-d H:i:s') . " - Sending message to URL: {$url}\n" .
            "Payload: " . json_encode($payload) . "\n",
            FILE_APPEND);

        @file_get_contents($url, false, stream_context_create(['http' => [
            'method' => 'POST',
            'ignore_errors' => true,
            'header' => "Accept: text/json\nContent-Type: text/json",
            'content' => json_encode($payload)
        ]]));
    }

    public function respond(array $payload) {
        $this->send($payload, $this->getReplyUrl());
    }

    public function notifyController(array $payload) {
        $this->send($payload, $this->getControllerUrl());
    }

    abstract public function authorized(): bool;
    abstract public function getClientId(): string;
}
