import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

/// Shows an OS notification when a private message arrives while the app is in
/// the foreground. Foreground only by design — when the app is backgrounded the
/// message listener stops, so nothing fires (background/push is a later, larger
/// concern). Web and Windows have no local-notification support, so there this
/// whole service is an inert no-op.
///
/// For privacy it never carries message text — the caller passes a generic
/// `New message from <name>` title (see [InboxService]). The peer's pubkey rides
/// along as the payload so a tap can open that exact chat via [onTapChat].
class NotificationService {
  NotificationService({
    FlutterLocalNotificationsPlugin? plugin,
    bool? supported,
  })  : _plugin = plugin ?? FlutterLocalNotificationsPlugin(),
        _supported = supported ?? _platformSupported;

  final FlutterLocalNotificationsPlugin _plugin;
  final bool _supported;
  bool _ready = false;

  /// Called with a peer pubkey when the user taps a message notification. The
  /// app wires this to `router.push('/chat/<pubkey>')` once the router exists.
  void Function(String peerPubkey)? onTapChat;

  static const _channelId = 'messages';

  static bool get _platformSupported {
    if (kIsWeb) return false;
    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
      case TargetPlatform.iOS:
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
        return true;
      case TargetPlatform.windows:
      case TargetPlatform.fuchsia:
        return false;
    }
  }

  /// Initialises the plugin and requests permission (Android 13+/iOS/macOS ask
  /// at runtime). Idempotent and safe to call on any platform.
  Future<void> initialize() async {
    if (!_supported || _ready) return;
    const android = AndroidInitializationSettings('@mipmap/ic_launcher');
    const darwin = DarwinInitializationSettings();
    const linux = LinuxInitializationSettings(defaultActionName: 'Open');
    await _plugin.initialize(
      const InitializationSettings(
        android: android,
        iOS: darwin,
        macOS: darwin,
        linux: linux,
      ),
      onDidReceiveNotificationResponse: (response) {
        final payload = response.payload;
        if (payload != null && payload.isNotEmpty) onTapChat?.call(payload);
      },
    );
    await _plugin
        .resolvePlatformSpecificImplementation<
            AndroidFlutterLocalNotificationsPlugin>()
        ?.requestNotificationsPermission();
    await _plugin
        .resolvePlatformSpecificImplementation<
            IOSFlutterLocalNotificationsPlugin>()
        ?.requestPermissions(alert: true, badge: true, sound: true);
    await _plugin
        .resolvePlatformSpecificImplementation<
            MacOSFlutterLocalNotificationsPlugin>()
        ?.requestPermissions(alert: true, badge: true, sound: true);
    _ready = true;
  }

  /// Shows a notification for a new message. [title] is a generic, text-free
  /// line like "New message from Alice"; [peerPubkey] becomes the tap payload.
  /// No-op on unsupported platforms.
  Future<void> showMessage({
    required String peerPubkey,
    required String title,
  }) async {
    if (!_supported) return;
    const details = NotificationDetails(
      android: AndroidNotificationDetails(
        _channelId,
        'Messages',
        channelDescription: 'New private messages',
        importance: Importance.high,
        priority: Priority.high,
      ),
      iOS: DarwinNotificationDetails(),
      macOS: DarwinNotificationDetails(),
      linux: LinuxNotificationDetails(),
    );
    // One notification per peer (same id replaces the previous), so a chatty
    // peer doesn't stack a wall of notifications.
    await _plugin.show(peerPubkey.hashCode, title, null, details,
        payload: peerPubkey);
  }
}
