<?php
// sendnotification.php - send a mention notification to @alcea@mas.to with logging

date_default_timezone_set('UTC');

$logFile = __DIR__ . '/notify.log';

function logNotify(string $msg) {
    global $logFile;
    file_put_contents($logFile, "[" . date('c') . "] $msg\n", FILE_APPEND);
}

function discoverInbox(string $actorUrl): ?string {
    logNotify("Fetching actor JSON from: $actorUrl");
    $actorUrl = rtrim($actorUrl, '/') . '.json';
    $ctx = stream_context_create([
        'http' => [
            'method' => 'GET',
            'header' => "Accept: application/activity+json, application/ld+json\r\n",
            'timeout' => 5,
        ]
    ]);
    $json = @file_get_contents($actorUrl, false, $ctx);
    if (!$json) {
        logNotify("Failed to fetch actor JSON from $actorUrl");
        return null;
    }
    $actor = json_decode($json, true);
    if (!$actor) {
        logNotify("Invalid JSON from actor URL $actorUrl");
        return null;
    }
    $inbox = $actor['inbox'] ?? null;
    if ($inbox) {
        logNotify("Discovered inbox: $inbox");
    } else {
        logNotify("Inbox not found in actor JSON");
    }
    return $inbox;
}

function sendSignedRequest(string $inboxUrl, array $body): bool {
    global $logFile;

    $privateKeyFile = __DIR__ . '/private.pem';
    $baseUrl = 'https://alceawis.com';
    $username = 'alceawis';

    logNotify("Preparing to send Create activity to $inboxUrl");

    $privateKeyPem = @file_get_contents($privateKeyFile);
    if (!$privateKeyPem) {
        logNotify("Private key file not found or unreadable.");
        return false;
    }

    $bodyJson = json_encode($body, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
    if ($bodyJson === false) {
        logNotify("Failed to encode JSON body for sending.");
        return false;
    }

    $digest = 'SHA-256=' . base64_encode(hash('sha256', $bodyJson, true));
    $date = gmdate('D, d M Y H:i:s \G\M\T');
    $urlParts = parse_url($inboxUrl);
    $host = $urlParts['host'] ?? '';
    $path = $urlParts['path'] ?? '/';

    $signatureString = "(request-target): post $path\nhost: $host\ndate: $date\ndigest: $digest";
    $privateKey = openssl_pkey_get_private($privateKeyPem);
    if (!$privateKey) {
        logNotify("Failed to load private key for signing.");
        return false;
    }
    $signatureOk = openssl_sign($signatureString, $signature, $privateKey, OPENSSL_ALGO_SHA256);
    // openssl_free_key() is deprecated; no call here
    if (!$signatureOk) {
        logNotify("Failed to create signature.");
        return false;
    }
    $signatureB64 = base64_encode($signature);
    $keyId = "$baseUrl/$username#main-key";

    $signatureHeader = sprintf(
        'keyId="%s",algorithm="rsa-sha256",headers="(request-target) host date digest",signature="%s"',
        $keyId,
        $signatureB64
    );

    $headers = [
        "Host: $host",
        "Date: $date",
        "Digest: $digest",
        "Signature: $signatureHeader",
        "Content-Type: application/activity+json"
    ];

    $ch = curl_init($inboxUrl);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $bodyJson,
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 10,
    ]);

    $response = curl_exec($ch);
    $curlError = curl_error($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($curlError) {
        logNotify("cURL error sending to $inboxUrl: $curlError");
        return false;
    }

    logNotify("Sent Create activity to $inboxUrl");
    logNotify("HTTP $httpCode");
    logNotify("Response: " . substr($response, 0, 300));

    return $httpCode >= 200 && $httpCode < 300;
}

// Main

logNotify("BEGIN sendnotification.php");
logNotify("REQUEST_URI: " . ($_SERVER['REQUEST_URI'] ?? ''));

$targetUser = 'https://mas.to/users/alcea';
$actorUrl = $targetUser . '.json';
$inbox = discoverInbox($targetUser);

if (!$inbox) {
    logNotify("No inbox discovered, aborting.");
    echo "No inbox discovered, aborting.\n";
    exit(1);
}

// Construct activity with mention tag and proper content to trigger Mastodon notification
$baseUrl = 'https://alceawis.com';
$username = 'alceawis';
$activityId = "$baseUrl/$username#notification-" . time();

$activity = [
    '@context' => 'https://www.w3.org/ns/activitystreams',
    'id' => $activityId,
    'type' => 'Create',
    'actor' => "$baseUrl/$username",
    'to' => [$targetUser],
    'cc' => ['https://www.w3.org/ns/activitystreams#Public'],
    'object' => [
        'id' => $activityId . '/object',
        'type' => 'Note',
        'attributedTo' => "$baseUrl/$username",
        'to' => [$targetUser],
        'cc' => ['https://www.w3.org/ns/activitystreams#Public'],
        'content' => 'Hello <a href="https://mas.to/users/alcea">@alcea</a>, check this status: <a href="https://alceawis.com/alceawis/status/20250718-71c7544a">https://alceawis.com/alceawis/status/20250718-71c7544a</a>',
        'tag' => [
            [
                'type' => 'Mention',
                'href' => $targetUser,
                'name' => '@alcea',
            ],
        ],
    ],
];

$sent = sendSignedRequest($inbox, $activity);

if ($sent) {
    echo "Notification complete\nSee notify.log for full logs.\n";
    logNotify("END sendnotification.php");
    exit(0);
} else {
    echo "Failed to send notification\nSee notify.log for details.\n";
    logNotify("Failed to send notification");
    logNotify("END sendnotification.php");
    exit(1);
}
