import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

import '../models/notification_item.dart';
import '../providers/notifications_provider.dart';
import '../providers/notification_navigation_provider.dart';
import '../routing/app_router.dart';

/// Wraps the app and installs both a Supabase realtime listener and the
/// FCM handlers described in the frontend design.
///
/// Navigation is performed via the [GoRouter] instance obtained from
/// [appRouterProvider], so this widget does **not** require an external
/// navigator key.
class NotificationBridge extends ConsumerStatefulWidget {
  const NotificationBridge({required this.child, super.key});

  final Widget child;

  @override
  ConsumerState<NotificationBridge> createState() => _NotificationBridgeState();
}

class _NotificationBridgeState extends ConsumerState<NotificationBridge>
    with WidgetsBindingObserver {
  // store previous notifications to diff
  List<NotificationItem> _prevList = [];

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _setupFcmHandlers();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    // App lifecycle is now monitored, but individual streams handle their own
    // recovery via StreamRecoveryWrapper. This no longer forces a global reconnect,
    // which was the blocking behavior users complained about.
    if (state == AppLifecycleState.resumed) {
      // Future: Could trigger stream-specific recovery hints if needed.
    }
  }

  /// Navigate to the task or ticket detail screen using GoRouter.
  void _goToDetail({String? taskId, String? ticketId}) {
    final router = ref.read(appRouterProvider);
    if (taskId != null && taskId.isNotEmpty) {
      router.go('/tasks/$taskId');
    } else if (ticketId != null && ticketId.isNotEmpty) {
      router.go('/tickets/$ticketId');
    }
  }

  void _showBanner(String type, NotificationItem item) {
    // Use a post-frame callback so that the ScaffoldMessenger from
    // MaterialApp is available in the element tree.
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) return;
      try {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('New $type received!'),
            action: SnackBarAction(
              label: 'View',
              onPressed: () =>
                  _goToDetail(taskId: item.taskId, ticketId: item.ticketId),
            ),
          ),
        );
      } catch (_) {
        // ScaffoldMessenger not available yet (before first frame) — ignore.
      }
    });
  }

  void _setupFcmHandlers() {
    // ignore foreground messages; realtime websocket will surface them
    FirebaseMessaging.onMessage.listen((_) {});

    // handle taps when the app is backgrounded
    FirebaseMessaging.onMessageOpenedApp.listen(_handleMessageTap);

    // handle a tap that launched the app from a terminated state
    FirebaseMessaging.instance.getInitialMessage().then((msg) {
      if (msg != null) _handleMessageTap(msg);
    });
  }

  /// Extract task/ticket IDs from the FCM data payload and navigate.
  ///
  /// The FCM data map contains keys such as `task_id` / `taskId` /
  /// `ticket_id` / `ticketId` — these are the same keys used in the
  /// background handler ([_firebaseMessagingBackgroundHandler]).
  void _handleMessageTap(RemoteMessage message) {
    final data = message.data;

    final String? taskId = (data['task_id'] ?? data['taskId'] ?? data['task'])
        ?.toString();
    final String? ticketId =
        (data['ticket_id'] ?? data['ticketId'] ?? data['ticket'])?.toString();

    _goToDetail(taskId: taskId, ticketId: ticketId);
  }

  @override
  Widget build(BuildContext context) {
    // listen inside build; safe with ConsumerState
    ref.listen<AsyncValue<List<NotificationItem>>>(notificationsProvider, (
      previous,
      next,
    ) {
      final prevList = _prevList;
      final nextList = next.maybeWhen(
        data: (d) => d,
        orElse: () => <NotificationItem>[],
      );
      if (nextList.length > prevList.length) {
        final newItem = nextList.last;
        _showBanner(newItem.type, newItem);
      }
      _prevList = nextList;
    });

    // Listen for pending navigation from local-notification taps
    ref.listen<PendingNavigation?>(pendingNotificationNavigationProvider, (
      previous,
      next,
    ) {
      if (next != null) {
        _goToDetail(
          taskId: next.type == 'task' ? next.id : null,
          ticketId: next.type == 'ticket' ? next.id : null,
        );
        // Clear the pending navigation after handling
        ref.read(pendingNotificationNavigationProvider.notifier).state = null;
      }
    });

    return widget.child;
  }
}
