<?php

namespace App\Services;

use App\Models\User;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class FcmService
{
    /**
     * Send a push notification to a specific user.
     */
    public static function sendToUser(User $user, string $title, string $body, array $data = [], ?string $imageUrl = null): bool
    {
        if (!$user->fcm_token) {
            Log::info("FCM: User {$user->id} does not have an FCM token. Skipping push.");
            return false;
        }

        return self::sendNotification($user->fcm_token, $title, $body, $data, false, $imageUrl);
    }

    /**
     * Broadcast a push notification to a topic.
     */
    public static function sendToTopic(string $topic, string $title, string $body, array $data = [], ?string $imageUrl = null): bool
    {
        return self::sendNotification('/topics/' . $topic, $title, $body, $data, true, $imageUrl);
    }

    /**
     * Core push notification sender using Firebase HTTP v1 API with JWT authentication.
     */
    private static function sendNotification(string $target, string $title, string $body, array $data = [], bool $isTopic = false, ?string $imageUrl = null): bool
    {
        $serviceAccountPath = storage_path('app/firebase-service-account.json');

        if (!file_exists($serviceAccountPath)) {
            Log::warning("FCM: firebase-service-account.json is missing in storage/app. Simulated push: Title: '$title', Body: '$body', Image: '$imageUrl'.");
            return true; // Return true as a fallback for simulated environments
        }

        try {
            $serviceAccount = json_decode(file_get_contents($serviceAccountPath), true);
            if (!$serviceAccount || !isset($serviceAccount['project_id']) || !isset($serviceAccount['private_key']) || !isset($serviceAccount['client_email'])) {
                Log::error("FCM: Invalid firebase-service-account.json format.");
                return false;
            }

            $accessToken = self::getGoogleAccessToken($serviceAccount);
            if (!$accessToken) {
                Log::error("FCM: Failed to obtain Google OAuth2 access token.");
                return false;
            }

            $projectId = $serviceAccount['project_id'];
            $url = "https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send";

            // Build request payload
            $notificationPayload = [
                'title' => $title,
                'body' => $body,
            ];

            if ($imageUrl) {
                $notificationPayload['image'] = $imageUrl;
            }

            $message = [
                'notification' => $notificationPayload,
            ];

            if (!empty($data)) {
                $message['data'] = array_map('strval', $data);
            }

            if ($isTopic) {
                $message['topic'] = str_replace('/topics/', '', $target);
            } else {
                $message['token'] = $target;
            }

            // Android specific settings for heads-up notifications
            $androidNotification = [
                'channel_id' => 'match_metrix_channel',
                'default_sound' => true,
                'default_vibrate_timings' => true,
            ];

            if ($imageUrl) {
                $androidNotification['image'] = $imageUrl;
            }

            $message['android'] = [
                'priority' => 'high',
                'notification' => $androidNotification
            ];

            // iOS (APNs) specific settings
            if ($imageUrl) {
                $message['apns'] = [
                    'payload' => [
                        'aps' => [
                            'mutable-content' => 1
                        ]
                    ],
                    'fcm_options' => [
                        'image' => $imageUrl
                    ]
                ];
            }

            $response = Http::withHeaders([
                'Authorization' => 'Bearer ' . $accessToken,
                'Content-Type' => 'application/json',
            ])->post($url, ['message' => $message]);

            if ($response->successful()) {
                Log::info("FCM push successfully sent to " . ($isTopic ? "topic: $target" : "token: " . substr($target, 0, 10) . "..."));
                return true;
            }

            Log::error("FCM push failed: " . $response->body());
            return false;

        } catch (\Exception $e) {
            Log::error("FCM send exception: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Generate an OAuth2 access token using RS256 JWT assertion (No external libraries required).
     */
    private static function getGoogleAccessToken(array $serviceAccount): ?string
    {
        try {
            $now = time();
            $header = base64UrlEncode(json_encode(['alg' => 'RS256', 'typ' => 'JWT']));
            
            $payload = base64UrlEncode(json_encode([
                'iss' => $serviceAccount['client_email'],
                'scope' => 'https://www.googleapis.com/auth/firebase.messaging',
                'aud' => 'https://oauth2.googleapis.com/token',
                'exp' => $now + 3600,
                'iat' => $now,
            ]));

            $signatureInput = $header . '.' . $payload;
            
            $privateKey = $serviceAccount['private_key'];
            $signature = '';
            
            if (!openssl_sign($signatureInput, $signature, $privateKey, OPENSSL_ALGO_SHA256)) {
                return null;
            }

            $jwt = $signatureInput . '.' . base64UrlEncode($signature);

            $response = Http::asForm()->post('https://oauth2.googleapis.com/token', [
                'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
                'assertion' => $jwt,
            ]);

            if ($response->successful()) {
                return $response->json()['access_token'] ?? null;
            }

            return null;
        } catch (\Exception $e) {
            Log::error("FCM Google Token retrieval failed: " . $e->getMessage());
            return null;
        }
    }
}

/**
 * Base64 URL Safe Encoding helper.
 */
if (!function_exists('base64UrlEncode')) {
    function base64UrlEncode(string $data): string
    {
        return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($data));
    }
}
