<?php
/* IJ-SLIP/2 R77H RN endpoint: G3/G4-compatible relay plus signed terminal selection. */
$requestHost = isset($_SERVER['HTTP_HOST']) ? strtolower(preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST'])) : '';
if ($requestHost === 'bypassjunky.ca' || $requestHost === 'www.bypassjunky.ca') {
    putenv('IJ_SLIP2_CONFIG=/home/joltsyst/ij-slip2/slipstream_v2_config.php');
}
$libraries = array(
    __DIR__ . '/slipstream_v2_lib.php',
    '/home/inteljun/ij-slip2/slipstream_v2_lib.php',
    '/home/joltsyst/ij-slip2/slipstream_v2_lib.php'
);
$libraryLoaded = false;
foreach ($libraries as $library) {
    if (is_file($library)) { require_once $library; $libraryLoaded = true; break; }
}
if (!$libraryLoaded) {
    http_response_code(503);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode(array('success' => false, 'code' => 'RN_LIBRARY_UNAVAILABLE'));
    exit;
}

try { $config = ss2_load_config(); }
catch (Exception $e) { ss2_json_response(503, array('success' => false, 'code' => 'CONFIG_UNAVAILABLE')); }

$nodeId = isset($config['node_id']) ? (string)$config['node_id'] : '';
$stageByNode = array(
    'RH-RN-PA-01' => '/home/inteljun/ij-slip2/final-rn-r77h',
    'RN-IS-01' => __DIR__ . '/.ij-slip2-private/final-rn-r77h',
    'RN-UA-01' => dirname(__DIR__) . '/ij-slip2/final-rn-r77h',
    'RN-CA-01' => '/home/joltsyst/ij-slip2/final-rn-r77h'
);
if (!isset($stageByNode[$nodeId])) {
    ss2_json_response(503, array('success' => false, 'code' => 'R77H_NODE_UNSUPPORTED'));
}
$stage = $stageByNode[$nodeId];
$selector = $stage . '/final_rn_selector_r77h.php';

if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'status') {
    ss2_json_response(200, array(
        'success' => true,
        'protocol' => 'IJ-SLIP/2',
        'node_id' => $nodeId,
        'roles' => $config['roles'],
        'final_rn_selection' => is_file($selector) ? 'SIGNED_G3_G4_READY' : 'UNAVAILABLE',
        'release' => 'R77H'
    ));
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    ss2_json_response(405, array('success' => false, 'code' => 'POST_REQUIRED'));
}

$request = ss2_request_json();
$tripId = isset($request['trip_id']) ? (string)$request['trip_id'] : '';
$capsule = isset($request['capsule']) ? (string)$request['capsule'] : '';
$binding = isset($_SERVER['HTTP_X_IJ_SPIKE_BINDING']) ? (string)$_SERVER['HTTP_X_IJ_SPIKE_BINDING'] : '';
if ($tripId === '' || $capsule === '' || $binding === '') {
    ss2_json_response(400, array('success' => false, 'code' => 'INVALID_REQUEST'));
}

try {
    $privatePath = isset($config['capsule_private_key_file']) ? (string)$config['capsule_private_key_file'] : '';
    $privatePem = $privatePath !== '' ? @file_get_contents($privatePath) : false;
    if ($privatePem === false) throw new RuntimeException('Node private key is unavailable');
    $payload = ss2_hybrid_open($capsule, $privatePem, 'capsule|' . $nodeId);
    if ($payload === false) ss2_json_response(403, array('success' => false, 'code' => 'CAPSULE_REJECTED'));
    foreach (array('protocol','trip_id','hop','node_id','expires_at','nonce','spike_binding','client_key','terminal') as $required) {
        if (!array_key_exists($required, $payload)) {
            ss2_json_response(403, array('success' => false, 'code' => 'CAPSULE_INCOMPLETE'));
        }
    }
    if ($payload['protocol'] !== 'IJ-SLIP/2' || $payload['trip_id'] !== $tripId || $payload['node_id'] !== $nodeId) {
        ss2_json_response(403, array('success' => false, 'code' => 'CAPSULE_MISMATCH'));
    }
    if (intval($payload['expires_at']) < time() || !hash_equals((string)$payload['spike_binding'], $binding)) {
        ss2_json_response(403, array('success' => false, 'code' => 'CAPSULE_EXPIRED_OR_UNBOUND'));
    }
    if (!ss2_consume_replay($config['replay_directory'], $tripId, intval($payload['hop']), (string)$payload['nonce'], intval($payload['expires_at']))) {
        ss2_json_response(409, array('success' => false, 'code' => 'CAPSULE_REPLAY'));
    }

    $clientKey = ss2_key_bytes((string)$payload['client_key']);
    $terminal = !empty($payload['terminal']);
    $step = array(
        'protocol' => 'IJ-SLIP/2',
        'trip_id' => $tripId,
        'hop' => intval($payload['hop']),
        'expires_at' => intval($payload['expires_at']),
        'next_endpoint' => isset($payload['next_endpoint']) ? $payload['next_endpoint'] : null,
        'next_capsule' => isset($payload['next_capsule']) ? $payload['next_capsule'] : null,
        'terminal' => $terminal
    );

    if ($terminal && isset($payload['route_request_nonce']) && is_string($payload['route_request_nonce']) && $payload['route_request_nonce'] !== '') {
        if (!is_file($selector)) throw new RuntimeException('R77H selector is unavailable');
        $manifestGeneration = isset($payload['manifest_generation']) ? intval($payload['manifest_generation']) : 3;
        $manifestHash = isset($payload['manifest_sha256']) ? strtolower((string)$payload['manifest_sha256']) : 'da300f16c362405da7919fe6116e3d86738ad83c24c6d23e800496d80e7b7352';
        if (!in_array($manifestGeneration, array(3, 4), true) || preg_match('/^[0-9a-f]{64}$/D', $manifestHash) !== 1) {
            throw new RuntimeException('R77H capsule manifest contract is invalid');
        }
        $expectedHashes = array(
            3 => 'da300f16c362405da7919fe6116e3d86738ad83c24c6d23e800496d80e7b7352',
            4 => '6c1f2e29611ee478f123d47fa3843c1200b125ad823c3359042d7cd8f98a7c4d'
        );
        if (!hash_equals($expectedHashes[$manifestGeneration], $manifestHash)) {
            throw new RuntimeException('R77H capsule manifest digest is not approved');
        }
        require_once $selector;
        $selection = ss2_final_rn_pick_mirror_r77h(
            array(
                'trip_id' => $tripId,
                'spike_binding' => (string)$payload['spike_binding'],
                'route_request_nonce' => (string)$payload['route_request_nonce']
            ),
            $nodeId,
            $privatePath,
            $stage . '/vanity-generation-' . $manifestGeneration . '.canonical.json',
            $stage . '/vanity-generation-' . $manifestGeneration . '.signature.bin',
            $stage . '/vanity-authority-public.pem',
            $manifestGeneration,
            $manifestHash
        );
        $step['next_endpoint'] = null;
        $step['next_capsule'] = null;
        $step['selection_payload_b64url'] = $selection['selection_payload_b64url'];
        $step['selection_signature_b64url'] = $selection['selection_signature_b64url'];
        $step['selection_key_id'] = $selection['selection_key_id'];
    } elseif ($terminal) {
        /* Pre-R77D capsules retain their already-selected Mirror destination. */
        if (empty($step['next_endpoint'])) throw new RuntimeException('Legacy terminal destination is absent');
    } elseif (empty($step['next_endpoint']) || empty($step['next_capsule'])) {
        throw new RuntimeException('Nonterminal route is incomplete');
    }

    $sealed = ss2_seal($step, $clientKey, 'step|' . $tripId . '|' . intval($payload['hop']));
    ss2_json_response(200, array('success' => true, 'protocol' => 'IJ-SLIP/2', 'step' => $sealed));
} catch (Exception $e) {
    ss2_json_response(503, array('success' => false, 'code' => 'HOP_UNAVAILABLE'));
}
