import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:googleapis_auth/auth_io.dart';
import 'package:logger/logger.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/services.dart' show rootBundle;

import 'package:marco/helpers/services/local_notification_service.dart';
import 'package:marco/helpers/services/storage/local_storage.dart';
import 'package:marco/helpers/services/auth_service.dart';
import 'package:marco/helpers/services/notification_action_handler.dart';

/// Firebase Notification Service
class FirebaseNotificationService {
  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
  final Logger _logger = Logger();

  static const _fcmScopes = [
    'https://www.googleapis.com/auth/firebase.messaging',
  ];

  /// Initialize FCM (Firebase.initializeApp() should be called once globally)
  Future<void> initialize() async {
    _logger.i('✅ FirebaseMessaging initializing...');

    await _requestNotificationPermission();
    _registerMessageListeners();
    _registerTokenRefreshListener();

    // Fetch token on app start (but only register with server if JWT available)
    await getFcmToken(registerOnServer: true);
  }

  /// Request notification permission
  Future<void> _requestNotificationPermission() async {
    final settings = await _firebaseMessaging.requestPermission();
    _logger.i('📩 Permission Status: ${settings.authorizationStatus}');
  }

  /// Foreground, background, and tap listeners
  void _registerMessageListeners() {
    FirebaseMessaging.onMessage.listen((message) {
      _logger.i('📩 Foreground Notification');
      _logNotificationDetails(message);

      // Handle custom actions
      NotificationActionHandler.handle(message.data);

      // Show local notification
      if (message.notification != null) {
        LocalNotificationService.showNotification(
          title: message.notification!.title ?? "No title",
          body: message.notification!.body ?? "No body",
        );
      }
    });

    FirebaseMessaging.onMessageOpenedApp.listen(_handleNotificationTap);

    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  }

  /// Token refresh handler
  void _registerTokenRefreshListener() {
    _firebaseMessaging.onTokenRefresh.listen((newToken) async {
      _logger.i('🔄 Token refreshed: $newToken');
      if (newToken.isEmpty) return;

      await LocalStorage.setFcmToken(newToken);

      final jwt = await LocalStorage.getJwtToken();
      if (jwt?.isNotEmpty ?? false) {
        final success = await AuthService.registerDeviceToken(newToken);
        _logger.i(success
            ? '✅ Device token updated on server after refresh.'
            : '⚠️ Failed to update device token on server.');
      } else {
        _logger.w('⚠️ JWT not available — will retry after login.');
      }
    });
  }

  /// Get current token (optionally sync to server if logged in)
  Future<String?> getFcmToken({bool registerOnServer = false}) async {
    try {
      final token = await _firebaseMessaging.getToken();
      _logger.i('🔑 FCM token: $token');

      if (token?.isNotEmpty ?? false) {
        await LocalStorage.setFcmToken(token!);

        if (registerOnServer) {
          final jwt = await LocalStorage.getJwtToken();
          if (jwt?.isNotEmpty ?? false) {
            final success = await AuthService.registerDeviceToken(token);
            _logger.i(success
                ? '✅ Device token registered on server.'
                : '⚠️ Failed to register device token on server.');
          } else {
            _logger.w('⚠️ JWT not available — skipping server registration.');
          }
        }
      }
      return token;
    } catch (e, s) {
      _logger.e('❌ Failed to get FCM token', error: e, stackTrace: s);
      return null;
    }
  }

  /// Re-register token with server (useful after login)
  Future<void> registerTokenAfterLogin() async {
    final token = await LocalStorage.getFcmToken();
    if (token?.isNotEmpty ?? false) {
      final success = await AuthService.registerDeviceToken(token!);
      _logger.i(success
          ? "✅ FCM token registered after login."
          : "⚠️ Failed to register FCM token after login.");
    }
  }

  /// Send a test notification using FCM v1 API
  Future<void> sendTestNotification(String deviceToken) async {
    try {
      final client = await _getAuthenticatedHttpClient();
      if (client == null) return;

      final projectId = await _getProjectId();
      if (projectId == null) return;

      _logger.i('🏗 Firebase Project ID: $projectId');

      final url = Uri.parse(
          'https://fcm.googleapis.com/v1/projects/$projectId/messages:send');
      final payload = _buildNotificationPayload(deviceToken);

      final response = await client.post(
        url,
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode(payload),
      );

      if (response.statusCode == 200) {
        _logger.i('✅ Test notification sent successfully');
      } else {
        _logger.e('❌ Send failed: ${response.statusCode} ${response.body}');
      }

      client.close();
    } catch (e, s) {
      _logger.e('❌ Error sending notification', error: e, stackTrace: s);
    }
  }

  /// Authenticated HTTP client using service account
  Future<http.Client?> _getAuthenticatedHttpClient() async {
    try {
      final credentials = ServiceAccountCredentials.fromJson(
        json.decode(await rootBundle.loadString('assets/service-account.json')),
      );
      return clientViaServiceAccount(credentials, _fcmScopes);
    } catch (e, s) {
      _logger.e('❌ Failed to authenticate', error: e, stackTrace: s);
      return null;
    }
  }

  /// Get Project ID from service account
  Future<String?> _getProjectId() async {
    try {
      final jsonMap = json
          .decode(await rootBundle.loadString('assets/service-account.json'));
      return jsonMap['project_id'];
    } catch (e) {
      _logger.e('❌ Failed to load project_id: $e');
      return null;
    }
  }

  /// Build FCM v1 payload
  Map<String, dynamic> _buildNotificationPayload(String token) => {
        "message": {
          "token": token,
          "notification": {
            "title": "Test Notification",
            "body": "This is a test message from Flutter (v1 API)"
          },
          "data": {
            "click_action": "FLUTTER_NOTIFICATION_CLICK",
            "type": "expense_updated", // Example
            "expense_id": "1234"
          },
        }
      };

  /// Handle tap on notification
  void _handleNotificationTap(RemoteMessage message) {
    _logger.i('📌 Notification tapped: ${message.data}');
    NotificationActionHandler.handle(message.data);
  }

  /// Log notification details
  void _logNotificationDetails(RemoteMessage message) {
    _logger
      ..i('🆔 ID: ${message.messageId}')
      ..i('📜 Title: ${message.notification?.title}')
      ..i('📜 Body: ${message.notification?.body}')
      ..i('📦 Data: ${message.data}');
  }
}

/// Background handler (required by Firebase)
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  final logger = Logger();
  logger
    ..i('⚡ Handling background notification...')
    ..i('📦 Data: ${message.data}');

  NotificationActionHandler.handle(message.data);
}
