<?php declare(strict_types=1);
/**
 * @package messenger
 * @author kputyr
 * @date 23.03.2026
 * 
 * This script authenticates connection to nchan locations
 */

namespace IMATHUZH\Messenger;

require_once 'request.php';

# Nchan interpretation of HTTP code:
#   200 OK            the response of this script is posted instead
#   204 No content    the message is deleted
#   304 Not modified  the message is posted on the channel

try {
    $authorized = false;    // Required for a notice to the controller
    $request = NchanRequest::fromServerRequest();

    # Check the existence of token and channel data
    $tokenId = $_SERVER['HTTP_AUTHORIZATION'] ?? reject('Authorization header missing');
    $group = $request->getChannelGroup() ?: reject('Channel group missing');

    # Read the token and authorize the access to the channel based on the requester's type
    session_name(NchanRequest::SESSION_NAME);
    session_start(['read_and_close' => true]);
    $token = SessionTokenManager::fromQfqSession()->loadToken($tokenId);
    switch ($request->getRequesterType()) {
        case 'publisher':
            $token->authorizesPublisher(
                $request->getChannelGroup(),
                $request->getPubChannels()
            ) or reject('Unauthorized publisher: allowed channels are ' . implode(",", $token->getPubChannels($group) ?? ['null']));
            break;
        case 'listener':
            $token->authorizesPublisher(
                $request->getChannelGroup(),
                $request->getPubChannels()
            ) or reject('Unauthorized publisher: allowed are ' . implode(",", $token->getPubChannels($group) ?? ['null']));
            $token->authorizesListener(
                $request->getChannelGroup(),
                $request->getSubChannels()
            ) or reject('Unauthorized subscriber: allowed are ' . implode(",", $token->getSubChannels($group) ?? ['null']));
            break;
        case 'controller':
            $token->authorizesController(
                $request->getChannelGroup(),
                $request->getSubChannels()
            ) or reject('Unauthorized controller: allowed are ' . implode(",", $token->getCtlChannels($group) ?? ['null']));
            break;
        default:
            reject('Unknown requester type: ' . $request->getRequesterType());
    }
    # Access allowed
    $request->authorize();
    $authorized = true;
} catch (\Exception $e) {
    $request->close(403, "Access denied");
    $error = $e->getMessage();
}

$payload = $request->getRequestMetaData();
$payload['authorized'] = $authorized;
if (isset($error)) $payload['error'] = $error;

$request->notifyController('auth', $payload);
