<?php
// ============================================================
// core/Services/FcmService.php
// إرسال FCM مع كاش توكن في Redis (بدل ملف)
// ============================================================

class FcmService
{
    private ?Redis $redis;
    private string $serviceAccountFile;

    public function __construct(?Redis $redis = null)
    {
        $this->redis              = $redis;
        // المسار بناء على بنية المشروع
        $this->serviceAccountFile = getenv('FIREBASE_SERVICE_ACCOUNT_PATH');
    }

    // ── إرسال إشعار ────────────────────────────────────────
    public function send(
        string $token,
        string $title,
        string $body,
        array  $data     = [],
        string $category = 'Order',
        string $tone     = 'ding'
    ): array {
        $accessToken = $this->getAccessToken();
        if (!$accessToken) {
            return ['status' => 'error', 'message' => 'No access token'];
        }

        if (!file_exists($this->serviceAccountFile)) {
             return ['status' => 'error', 'message' => 'Service account file missing'];
        }

        $creds     = json_decode(file_get_contents($this->serviceAccountFile), true);
        $projectId = $creds['project_id'];
        $fcmUrl    = "https://fcm.googleapis.com/v1/projects/$projectId/messages:send";

        $finalData = array_merge($data, [
            'title'    => $title,
            'body'     => $body,
            'tone'     => $tone,
            'category' => $category,
            'type'     => $category,
        ]);

        // FCM يشترط أن تكون كل القيم strings
        $processedData = array_map(
            fn($v) => is_array($v) || is_object($v)
                ? json_encode($v, JSON_UNESCAPED_UNICODE)
                : (string)$v,
            $finalData
        );

        $payload = [
            'message' => [
                'token'   => $token,
                'data'    => $processedData,
                'android' => ['priority' => 'HIGH'],
                'apns'    => [
                    'headers' => ['apns-priority' => '10', 'apns-push-type' => 'background'],
                    'payload' => ['aps' => ['content-available' => 1]],
                ],
            ],
        ];

        if (!empty($title) && !empty($body)) {
            $payload['message']['notification'] = [
                'title' => $title,
                'body'  => $body,
            ];
        }

        $ch = curl_init($fcmUrl);
        curl_setopt_array($ch, [
            CURLOPT_POST          => true,
            CURLOPT_HTTPHEADER    => [
                "Authorization: Bearer $accessToken",
                'Content-Type: application/json; charset=UTF-8',
            ],
            CURLOPT_POSTFIELDS    => json_encode($payload, JSON_UNESCAPED_UNICODE),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT       => 8,
            CURLOPT_CONNECTTIMEOUT => 3,
            CURLOPT_FRESH_CONNECT  => false, // إعادة استخدام الاتصال
            CURLOPT_FORBID_REUSE   => false,
            CURLOPT_TCP_KEEPALIVE  => 1,
        ]);

        $result   = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlErr  = curl_errno($ch);
        curl_close($ch);

        if ($curlErr) {
            return ['status' => 'error', 'message' => 'CURL error'];
        }

        return $httpCode === 200
            ? ['status' => 'success']
            : ['status' => 'error', 'code' => $httpCode, 'response' => $result];
    }

    // ── Access Token مع Redis Cache ─────────────────────────
    private function getAccessToken(): ?string
    {
        // 1. من Redis
        if ($this->redis) {
            $cached = $this->redis->get('google_fcm_access_token');
            if ($cached) return $cached;
        }

        // 2. طلب جديد
        $token = $this->fetchGoogleToken();

        if ($token && $this->redis) {
            $this->redis->setex('google_fcm_access_token', 3500, $token);
        }

        return $token;
    }

    private function fetchGoogleToken(): ?string
    {
        if (!file_exists($this->serviceAccountFile)) return null;

        $creds       = json_decode(file_get_contents($this->serviceAccountFile), true);
        $clientEmail = $creds['client_email'];
        $privateKey  = $creds['private_key'];
        $now         = time();

        $header  = rtrim(strtr(base64_encode(json_encode(['alg' => 'RS256', 'typ' => 'JWT'])), '+/', '-_'), '=');
        $claim   = rtrim(strtr(base64_encode(json_encode([
            'iss'   => $clientEmail,
            'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
            'aud'   => 'https://oauth2.googleapis.com/token',
            'exp'   => $now + 3600,
            'iat'   => $now,
        ])), '+/', '-_'), '=');

        $signature = '';
        openssl_sign("$header.$claim", $signature, $privateKey, 'SHA256');
        $jwt = "$header.$claim." . rtrim(strtr(base64_encode($signature), '+/', '-_'), '=');

        $ch = curl_init('https://oauth2.googleapis.com/token');
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query([
                'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
                'assertion'  => $jwt,
            ]),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 10,
        ]);

        $res = curl_exec($ch);
        curl_close($ch);

        return json_decode($res, true)['access_token'] ?? null;
    }
}
