import 'dart:developer';

import 'package:eraser/eraser.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app_badge/flutter_app_badge.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../push/chat_thread_store.dart';
import '../routing/app_routes.dart';
import '../state/app/modules/chat_list/bloc/chat_list_bloc.dart';
import 'notification_service.dart';

class NotificationTasks {
  /// Recomputes the app badge from the notifications currently in the tray.
  /// Deterministic — no server-provided counter to drift out of sync — so the
  /// badge always matches what the user actually sees. Called after rendering,
  /// cancelling, or opening the app.
  static Future<void> refreshBadge() async {
    try {
      final plugin = NotificationService().flutterLocalNotificationsPlugin;
      final actives = await plugin.getActiveNotifications();
      await FlutterAppBadge.count(actives.length);
    } on Object catch (e) {
      log('Badge refresh failed: $e');
    }
  }

  /// Per-chat tag scheme — canonical definition lives beside the stacked
  /// notification id in chat_thread_store.dart.
  static String chatTag(String chatToken) => chatNotificationTag(chatToken);

  /// Removes tray notifications belonging to [chatToken]. Eraser handles
  /// iOS (where the plugin's `getActiveNotifications` returns null ids
  /// for FCM posts and can't cancel them); the local-notifications sweep
  /// handles Android and acts as a fallback while Eraser's native side
  /// isn't built in yet.
  static Future<void> clearNotificationsForChat(String chatToken) async {
    final tag = chatTag(chatToken);
    try {
      await Eraser.clearAppNotificationsByTag(tag);
    } on MissingPluginException {
      // Eraser native code not yet linked — needs flutter clean + run.
    } on Object catch (e) {
      log('Eraser($tag) failed: $e');
    }
    try {
      final plugin = NotificationService().flutterLocalNotificationsPlugin;
      final actives = await plugin.getActiveNotifications();
      for (final n in actives) {
        final id = n.id;
        if (id == null) continue;
        if (n.tag == tag) await plugin.cancel(id: id, tag: n.tag);
      }
    } on Object catch (e) {
      log('Active-notification sweep failed: $e');
    }
    // Drop the stacked-notification history too — otherwise the next push
    // would resurrect all already-read messages in the new notification.
    try {
      await ChatThreadStore().clearChat(chatToken);
    } on Object catch (e) {
      log('Chat thread cleanup failed: $e');
    }
  }

  /// Refreshes the chat list. Deliberately does NOT touch [ChatBloc] —
  /// the open chat view manages its own state via long-poll, and refreshing
  /// it here would re-fetch the last-opened chat with setReadMarker=on
  /// even if the user has already left.
  static void updateProviders(BuildContext context) {
    context.read<ChatListBloc>().refresh();
  }

  /// Switches to the Talk tab. If [chatToken] is provided, also schedules
  /// the matching chat to be opened automatically once the chat list view
  /// resolves the token (handled inside [ChatList]).
  static void navigateToTalk(BuildContext context, {String? chatToken}) {
    if (chatToken != null && chatToken.isNotEmpty) {
      AppRoutes.openChatByToken(context, chatToken);
    } else {
      AppRoutes.goToTalkTab(context);
    }
  }
}
