<?php
declare(strict_types=1);

function mainppBase64Url(string $value): string
{
    return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
}

function mainppFirebaseCredentials(): ?array
{
    $path = trim((string) getenv('MAINPP_FIREBASE_SERVICE_ACCOUNT'));
    $push_config_path = dirname(__DIR__) . '/config/push_config.php';
    if ($path === '' && is_file($push_config_path)) {
        $push_config = require $push_config_path;
        if (is_array($push_config)) {
            $path = trim((string) ($push_config['firebase_service_account'] ?? ''));
        }
    }
    if ($path === '') $path = dirname(__DIR__) . '/config/firebase-service-account.json';
    if (!is_file($path)) return null;
    $decoded = json_decode((string) file_get_contents($path), true);
    return is_array($decoded) ? $decoded : null;
}

function mainppFirebaseAccessToken(array $credentials): ?string
{
    $cache_file = sys_get_temp_dir() . '/mainpp_fcm_' . sha1((string) ($credentials['client_email'] ?? '')) . '.json';
    if (is_file($cache_file)) {
        $cached = json_decode((string) file_get_contents($cache_file), true);
        if (is_array($cached) && (int) ($cached['expires_at'] ?? 0) > time() + 120) {
            return (string) ($cached['token'] ?? '');
        }
    }

    $now = time();
    $header = mainppBase64Url(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
    $claims = mainppBase64Url(json_encode([
        'iss' => (string) ($credentials['client_email'] ?? ''),
        'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
        'aud' => (string) ($credentials['token_uri'] ?? 'https://oauth2.googleapis.com/token'),
        'iat' => $now,
        'exp' => $now + 3600,
    ]));
    $unsigned = $header . '.' . $claims;
    $signature = '';
    if (!openssl_sign($unsigned, $signature, (string) ($credentials['private_key'] ?? ''), OPENSSL_ALGO_SHA256)) {
        return null;
    }
    $jwt = $unsigned . '.' . mainppBase64Url($signature);
    $token_uri = (string) ($credentials['token_uri'] ?? 'https://oauth2.googleapis.com/token');
    $curl = curl_init($token_uri);
    curl_setopt_array($curl, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 15,
        CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
        CURLOPT_POSTFIELDS => http_build_query([
            'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
            'assertion' => $jwt,
        ]),
    ]);
    $response = curl_exec($curl);
    $status = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
    curl_close($curl);
    $decoded = json_decode(is_string($response) ? $response : '', true);
    if ($status < 200 || $status >= 300 || !is_array($decoded) || empty($decoded['access_token'])) return null;

    $token = (string) $decoded['access_token'];
    @file_put_contents($cache_file, json_encode([
        'token' => $token,
        'expires_at' => $now + (int) ($decoded['expires_in'] ?? 3600),
    ]), LOCK_EX);
    return $token;
}

function sendMainppPush(mysqli $conn, int $user_id, string $title, string $body, array $data = []): array
{
    $credentials = mainppFirebaseCredentials();
    if (!$credentials) return ['success' => false, 'message' => 'Firebase service account belum dikonfigurasi.'];
    $access_token = mainppFirebaseAccessToken($credentials);
    if (!$access_token) return ['success' => false, 'message' => 'Firebase access token gagal dijana.'];

    $stmt = mysqli_prepare($conn, 'SELECT id, token FROM push_devices WHERE user_id = ? AND enabled = 1');
    mysqli_stmt_bind_param($stmt, 'i', $user_id);
    mysqli_stmt_execute($stmt);
    $result = mysqli_stmt_get_result($stmt);
    $sent = 0;
    $failed = 0;
    $errors = [];
    while ($device = mysqli_fetch_assoc($result)) {
        $string_data = [];
        foreach ($data as $key => $value) $string_data[(string) $key] = is_scalar($value) ? (string) $value : json_encode($value);
        $message = ['message' => [
            'token' => (string) $device['token'],
            'notification' => ['title' => $title, 'body' => $body],
            'data' => $string_data,
            'android' => ['priority' => 'high', 'notification' => ['channel_id' => 'mainpp_workspace_priority', 'sound' => 'default', 'default_sound' => true, 'default_vibrate_timings' => true, 'notification_priority' => 'PRIORITY_MAX', 'visibility' => 'PUBLIC']],
            'apns' => ['headers' => ['apns-priority' => '10'], 'payload' => ['aps' => ['sound' => 'default', 'content-available' => 1]]],
        ]];
        $url = 'https://fcm.googleapis.com/v1/projects/' . rawurlencode((string) $credentials['project_id']) . '/messages:send';
        $curl = curl_init($url);
        curl_setopt_array($curl, [
            CURLOPT_POST => true,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT => 15,
            CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $access_token, 'Content-Type: application/json'],
            CURLOPT_POSTFIELDS => json_encode($message),
        ]);
        $response = curl_exec($curl);
        $status = (int) curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);
        if ($status >= 200 && $status < 300) {
            $sent++;
        } else {
            $failed++;
            $response_text = is_string($response) ? $response : '';
            $errors[] = [
                'device_id' => (int) $device['id'],
                'status' => $status,
                'response' => substr($response_text, 0, 1000),
            ];
            if (str_contains($response_text, 'UNREGISTERED') || str_contains($response_text, 'NOT_FOUND')) {
                $disable = mysqli_prepare($conn, 'UPDATE push_devices SET enabled = 0 WHERE id = ?');
                $device_id = (int) $device['id'];
                mysqli_stmt_bind_param($disable, 'i', $device_id);
                mysqli_stmt_execute($disable);
            }
        }
    }
    return ['success' => $sent > 0, 'sent' => $sent, 'failed' => $failed, 'errors' => $errors];
}

function sendMainppPushToParticipantLabels(
    mysqli $conn,
    array $labels,
    int $exclude_user_id,
    string $title,
    string $body,
    array $data = []
): array {
    $labels = array_values(array_unique(array_filter(array_map(
        static fn($value): string => trim((string) $value),
        $labels
    ))));
    if (empty($labels)) return ['success' => true, 'sent' => 0, 'failed' => 0];

    $lookup = mysqli_prepare(
        $conn,
        "SELECT id FROM users
         WHERE status = 'approved'
           AND id <> ?
           AND (LOWER(fullname) = LOWER(?) OR LOWER(short_name) = LOWER(?) OR LOWER(email) = LOWER(?))
         LIMIT 1"
    );
    if (!$lookup) return ['success' => false, 'sent' => 0, 'failed' => count($labels)];

    $user_ids = [];
    foreach ($labels as $label) {
        mysqli_stmt_bind_param($lookup, 'isss', $exclude_user_id, $label, $label, $label);
        mysqli_stmt_execute($lookup);
        $row = mysqli_fetch_assoc(mysqli_stmt_get_result($lookup));
        $matched_user_id = (int) ($row['id'] ?? 0);
        if ($matched_user_id > 0) $user_ids[$matched_user_id] = true;
    }

    $sent = 0;
    $failed = 0;
    foreach (array_keys($user_ids) as $user_id) {
        $result = sendMainppPush($conn, (int) $user_id, $title, $body, $data);
        $sent += (int) ($result['sent'] ?? 0);
        $failed += (int) ($result['failed'] ?? 0);
    }
    return ['success' => $failed === 0, 'sent' => $sent, 'failed' => $failed];
}
