<?php
function getFCMAccessToken() {
    $serviceAccountPath = '/home/sssc3358/private/iview-5e2d8-firebase-adminsdk-fbsvc-d16916c5da.json';
    $serviceAccount = json_decode(file_get_contents($serviceAccountPath), true);

    $now = time();
    $expiry = $now + 3600;

    $header = base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
    $payload = base64_encode(json_encode([
        'iss' => $serviceAccount['client_email'],
        'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
        'aud' => 'https://oauth2.googleapis.com/token',
        'iat' => $now,
        'exp' => $expiry
    ]));

    $header = str_replace(['+', '/', '='], ['-', '_', ''], $header);
    $payload = str_replace(['+', '/', '='], ['-', '_', ''], $payload);

    $signInput = $header . '.' . $payload;
    $privateKey = openssl_pkey_get_private($serviceAccount['private_key']);
    openssl_sign($signInput, $signature, $privateKey, 'SHA256');
    $signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

    $jwt = $signInput . '.' . $signature;

    $ch = curl_init('https://oauth2.googleapis.com/token');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' => $jwt
    ]));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);

    $data = json_decode($response, true);
    return $data['access_token'] ?? null;
}

function sendFCMNotification($pdo, $fcmToken, $title, $body, $data = []) {
    $serviceAccount = json_decode(file_get_contents('/home/sssc3358/private/iview-5e2d8-firebase-adminsdk-fbsvc-d16916c5da.json'), true);
    $projectId = $serviceAccount['project_id'];
    $accessToken = getFCMAccessToken();

    if (!$accessToken) {
        error_log("FCM: Failed to get access token");
        return false;
    }

    $message = [
        'message' => [
            'token' => $fcmToken,
            'notification' => [
                'title' => $title,
                'body' => $body
            ],
            'data' => array_map('strval', $data),
            'android' => [
                'priority' => 'high',
                'notification' => [
                    'channel_id' => 'iview_notifications'
                ]
            ]
        ]
    ];

    $ch = curl_init("https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send");
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($message));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: Bearer ' . $accessToken,
        'Content-Type: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode === 200) {
        return true;
    } else {
        error_log("FCM Error ($httpCode): " . $result);
        $response = json_decode($result, true);
        $errorCode = $response['error']['details'][0]['errorCode'] ?? '';
        if ($errorCode === 'UNREGISTERED' || $httpCode === 404) {
            $pdo->prepare("UPDATE fcm_devices SET is_active = 0 WHERE fcm_token = ?")
                ->execute([$fcmToken]);
            error_log("FCM: Token dinonaktifkan - $fcmToken");
        }
        return false;
    }
}

function sendFCMToUser($pdo, $userId, $title, $body, $data = []) {
    $stmt = $pdo->prepare("SELECT fcm_token FROM fcm_devices WHERE user_id = ? AND is_active = 1");
    $stmt->execute([$userId]);
    $devices = $stmt->fetchAll();

    $successCount = 0;
    foreach ($devices as $device) {
        $success = sendFCMNotification($pdo, $device['fcm_token'], $title, $body, $data);
        if ($success) $successCount++;
    }
    return $successCount;
}

function sendFCMToCompany($pdo, $companyId, $title, $body, $data = []) {
    $stmt = $pdo->prepare("
        SELECT fd.fcm_token FROM fcm_devices fd
        JOIN user_account ua ON fd.user_id = ua.id
        WHERE ua.company = ? AND fd.is_active = 1
    ");
    $stmt->execute([$companyId]);
    $devices = $stmt->fetchAll();

    $successCount = 0;
    foreach ($devices as $device) {
        $success = sendFCMNotification($pdo, $device['fcm_token'], $title, $body, $data);
        if ($success) $successCount++;
    }
    return $successCount;
}

// ─── Web Push ────────────────────────────────────────────────────────────────

function sendWebPushNotification($endpoint, $p256dh, $auth, $title, $body, $data = []) {
    require_once __DIR__ . '/config/vapid.php';

    $payload = json_encode([
        'title' => $title,
        'body'  => $body,
        'data'  => $data
    ]);

    // Enkripsi payload pakai p256dh + auth
    $encrypted = encryptWebPushPayload($payload, $p256dh, $auth);
    if (!$encrypted) {
        error_log("WebPush: Enkripsi gagal");
        return false;
    }

    // VAPID Authorization header
    $vapidAuth = buildVapidHeader($endpoint);

    $ch = curl_init($endpoint);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $encrypted['ciphertext']);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Authorization: ' . $vapidAuth,
        'Content-Type: application/octet-stream',
        'Content-Encoding: aes128gcm',
        'TTL: 86400',
        'Urgency: normal'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($httpCode >= 200 && $httpCode < 300) {
        return true;
    } else {
        error_log("WebPush Error ($httpCode): $result endpoint: $endpoint");
        return false;
    }
}

function encryptWebPushPayload($payload, $p256dhBase64, $authBase64) {
    $p256dh = base64_decode(str_pad(strtr($p256dhBase64, '-_', '+/'), strlen($p256dhBase64) % 4 === 0 ? strlen($p256dhBase64) : strlen($p256dhBase64) + 4 - strlen($p256dhBase64) % 4, '='));
    $auth   = base64_decode(str_pad(strtr($authBase64, '-_', '+/'), strlen($authBase64) % 4 === 0 ? strlen($authBase64) : strlen($authBase64) + 4 - strlen($authBase64) % 4, '='));

    // Generate server EC key pair
    $serverKey = openssl_pkey_new(['curve_name' => 'prime256v1', 'private_key_type' => OPENSSL_KEYTYPE_EC]);
    $serverDetails = openssl_pkey_get_details($serverKey);
    $serverPublicKey = "\x04" . $serverDetails['ec']['x'] . $serverDetails['ec']['y'];

    // Client public key (uncompressed point)
    $clientPublicKey = "\x04" . substr($p256dh, 1); // strip leading 0x04 if present, add back

    // ECDH
    $clientKey = openssl_pkey_get_public(['key' => $p256dh, 'curve_name' => 'prime256v1']);
    openssl_pkey_export($serverKey, $serverPrivPem);
    $serverPriv = openssl_pkey_get_private($serverPrivPem);

    // Derive shared secret via ECDH
    $sharedSecret = '';
    if (!openssl_derive_key($serverPriv, $p256dh, $sharedSecret, 'prime256v1')) {
        // Fallback manual ECDH
        return null;
    }

    $salt = random_bytes(16);

    // HKDF
    $prk = hash_hmac('sha256', $sharedSecret, $auth, true);
    $keyInfo = "Content-Encoding: aes128gcm\x00\x01";
    $nonceInfo = "Content-Encoding: nonce\x00\x01";

    $ikm = hash_hmac('sha256', $sharedSecret, $auth . "WebPush: info\x00" . $p256dh . $serverPublicKey, true);
    $prk2 = hash_hmac('sha256', $ikm, $salt, true);

    $contentKey = substr(hash_hmac('sha256', $prk2, $keyInfo, true), 0, 16);
    $nonce = substr(hash_hmac('sha256', $prk2, $nonceInfo, true), 0, 12);

    $paddedPayload = $payload . "\x02";
    $tag = '';
    $ciphertext = openssl_encrypt($paddedPayload, 'aes-128-gcm', $contentKey, OPENSSL_RAW_DATA, $nonce, $tag);

    // aes128gcm header
    $header = $salt
        . pack('N', 4096)       // record size
        . pack('C', strlen($serverPublicKey))
        . $serverPublicKey;

    return ['ciphertext' => $header . $ciphertext . $tag];
}

function buildVapidHeader($endpoint) {
    require_once __DIR__ . '/config/vapid.php';

    $parsed = parse_url($endpoint);
    $audience = $parsed['scheme'] . '://' . $parsed['host'];

    $now = time();
    $header  = rtrim(strtr(base64_encode(json_encode(['typ'=>'JWT','alg'=>'ES256'])), '+/', '-_'), '=');
    $payload = rtrim(strtr(base64_encode(json_encode([
        'aud' => $audience,
        'exp' => $now + 43200,
        'sub' => VAPID_SUBJECT
    ])), '+/', '-_'), '=');

    $sigInput = $header . '.' . $payload;
    $privateKeyPem = base64_decode(VAPID_PRIVATE_KEY);
    $privKey = openssl_pkey_get_private($privateKeyPem);
    openssl_sign($sigInput, $sig, $privKey, 'SHA256');

    // Convert DER signature to raw r||s (64 bytes)
    $sig = derToRaw($sig);
    $sigB64 = rtrim(strtr(base64_encode($sig), '+/', '-_'), '=');

    $pubKeyB64 = VAPID_PUBLIC_KEY;

    return "vapid t=$sigInput.$sigB64,k=$pubKeyB64";
}

function derToRaw($der) {
    // ASN.1 DER ECDSA signature → raw r||s
    $offset = 2; // skip SEQUENCE tag + length
    if (ord($der[1]) & 0x80) $offset += ord($der[1]) & 0x7f;
    $offset++; // INTEGER tag
    $rLen = ord($der[$offset++]);
    $r = substr($der, $offset, $rLen); $offset += $rLen;
    $offset++; // INTEGER tag
    $sLen = ord($der[$offset++]);
    $s = substr($der, $offset, $sLen);
    // Pad/trim to 32 bytes each
    $r = str_pad(ltrim($r, "\x00"), 32, "\x00", STR_PAD_LEFT);
    $s = str_pad(ltrim($s, "\x00"), 32, "\x00", STR_PAD_LEFT);
    return $r . $s;
}

function sendWebPushToCompany($pdo, $companyId, $title, $body, $data = []) {
    $stmt = $pdo->prepare("
        SELECT ws.endpoint, ws.p256dh, ws.auth FROM webpush_subscriptions ws
        JOIN user_account ua ON ws.user_id = ua.id
        WHERE ua.company = ?
    ");
    $stmt->execute([$companyId]);
    $subs = $stmt->fetchAll();

    $successCount = 0;
    foreach ($subs as $sub) {
        $ok = sendWebPushNotification($sub['endpoint'], $sub['p256dh'], $sub['auth'], $title, $body, $data);
        if ($ok) $successCount++;
    }
    return $successCount;
}

function sendWebPushToUser($pdo, $userId, $title, $body, $data = []) {
    $stmt = $pdo->prepare("SELECT endpoint, p256dh, auth FROM webpush_subscriptions WHERE user_id = ?");
    $stmt->execute([$userId]);
    $subs = $stmt->fetchAll();

    $successCount = 0;
    foreach ($subs as $sub) {
        $ok = sendWebPushNotification($sub['endpoint'], $sub['p256dh'], $sub['auth'], $title, $body, $data);
        if ($ok) $successCount++;
    }
    return $successCount;
}
?>