import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:fis_common/event/event_type.dart';
import 'package:fis_i18n/i18n.dart';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

/// 移动端系统通知服务
///
/// 必须在 runApp 之前调用 localNotificationServiceGlobalInit 初始化
class LocalNotificationService extends GetxService {
  LocalNotificationService();
  // 消息 id
  int id = 0;

  /// 获取到启动时的负载消息
  Payload? selectedNotificationPayload;

  /// 是否由通知栏启动
  bool isLaunchFromNotification = false;

  /// 应用存活时点击通知的消息回调
  final FEventHandler<Payload> onNotificationClick = FEventHandler<Payload>();

  /// 通知栏消息插件
  static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
      FlutterLocalNotificationsPlugin();

  /// 绕过通知栏的应用内消息回调（darwin 内核专属）
  static final StreamController<ReceivedNotification>
      didReceiveLocalNotificationStream =
      StreamController<ReceivedNotification>.broadcast();

  /// 选中消息栏内消息通知的回调
  static final StreamController<String?> selectNotificationStream =
      StreamController<String?>.broadcast();

  /// 统一通知入口
  ///
  /// [title] 通知标题
  ///
  /// [info] 通知内容
  ///
  /// [detailTitle] 展开详情下的标题-仅支持 Android
  ///
  /// [detailInfos] 展开详情下的内容-仅支持 Android
  ///
  /// [![3UzG3.md.png](https://i.328888.xyz/2023/02/08/3UzG3.md.png)](https://imgloc.com/i/3UzG3)
  Future<void> showNotification(
    String title,
    String info,
    String detailTitle,
    List<String> detailInfos,
    Payload payload,
  ) async {
    /// 如果是 Android 则使用 _showInboxNotification，否则使用 _showNomalNotification
    if (Platform.isAndroid) {
      await _showInboxNotification(
        title,
        info,
        detailTitle,
        detailInfos,
        payload,
      );
    } else {
      await _showNomalNotification(
        title,
        info,
        payload,
      );
    }
  }

  // 普通文本通知
  Future<void> _showNomalNotification(
    String title,
    String info,
    Payload payload,
  ) async {
    AndroidNotificationDetails androidNotificationDetails =
        AndroidNotificationDetails(
      'com.vinno.flyinsono.next',
      i18nBook.notification.messageReminder.t,
      channelDescription: i18nBook.notification.messageReminderFromFlyinsono.t,
      importance: Importance.max,
      priority: Priority.high,
      ticker: 'ticker',
      icon: '@mipmap/ic_launcher',
    );
    NotificationDetails notificationDetails =
        NotificationDetails(android: androidNotificationDetails);
    await flutterLocalNotificationsPlugin.show(
      id++,
      title,
      info,
      notificationDetails,
      payload: payload.toString(),
    );
  }

  // 显示盒内通知 [多行]
  // 在通知栏收起时只显示 [inbox title] [inbox body]
  // 展开后显示其余信息
  Future<void> _showInboxNotification(
    String title,
    String info,
    String detailTitle,
    List<String> detailInfos,
    Payload payload,
  ) async {
    final InboxStyleInformation inboxStyleInformation = InboxStyleInformation(
      detailInfos,
      htmlFormatLines: true,
      contentTitle: detailTitle,
      htmlFormatContentTitle: true,
      // summaryText: null,
      htmlFormatSummaryText: true,
    );
    final AndroidNotificationDetails androidNotificationDetails =
        AndroidNotificationDetails(
      'com.vinno.flyinsono.next',
      i18nBook.notification.messageReminder.t,
      channelDescription: i18nBook.notification.messageReminderFromFlyinsono.t,
      styleInformation: inboxStyleInformation,
      icon: '@mipmap/ic_launcher',
    );
    final NotificationDetails notificationDetails =
        NotificationDetails(android: androidNotificationDetails);
    await flutterLocalNotificationsPlugin.show(
      id++,
      title,
      info,
      notificationDetails,
      payload: payload.toString(),
    );
  }

  // 取消最新通知
  Future<void> cancelNotification() async {
    await flutterLocalNotificationsPlugin.cancel(--id);
  }

  // 取消所有通知
  Future<void> cancelAllNotifications() async {
    await flutterLocalNotificationsPlugin.cancelAll();
  }

  // 获取并加载由通知栏启动 app 时传入的参数
  void loadLaunchPayload({
    required void Function(Payload payload) method,
  }) async {
    if (!isLaunchFromNotification) return;
    isLaunchFromNotification = false;
    method(selectedNotificationPayload!);
  }

  @override
  void onInit() async {
    super.onInit();
    _initNotificationConfig();
    _initPermission();
    _configSubjects();
  }

  @override
  void onClose() {
    didReceiveLocalNotificationStream.close();
    selectNotificationStream.close();
    super.onClose();
  }

  /// 初始化通知栏消息配置
  void _initNotificationConfig() async {
    /// Linux 下不支持通知栏消息，所以不需要启动参数，其他平台可以取到启动参数
    final NotificationAppLaunchDetails? notificationAppLaunchDetails =
        !kIsWeb && Platform.isLinux
            ? null
            : await flutterLocalNotificationsPlugin
                .getNotificationAppLaunchDetails();

    /// 如果是通过点击通知栏内的消息通知启动的应用，那么传入负载消息
    if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
      isLaunchFromNotification = true;
      selectedNotificationPayload = Payload.fromString(
          notificationAppLaunchDetails!.notificationResponse?.payload);
    }
  }

  /// 全局初始化，必须保证在 runApp 之前调用
  static Future<void> init() async {
    /// 初始化安卓的消息通知配置
    const AndroidInitializationSettings initializationSettingsAndroid =
        AndroidInitializationSettings('@mipmap/ic_launcher');

    /// 预定义可交互的消息通知目录 [暂时不用]
    final List<DarwinNotificationCategory> darwinNotificationCategories =
        <DarwinNotificationCategory>[];

    /// /// 初始化安卓的消息通知配置
    /// 注意：此处不要求权限只是为了证明可以在之后完成
    final DarwinInitializationSettings initializationSettingsDarwin =
        DarwinInitializationSettings(
      requestAlertPermission: false,
      requestBadgePermission: false,
      requestSoundPermission: false,

      /// 收到应用消息通知后的回调
      /// darwin 内核下，如果应用在前台，会直接回调，不会走通知栏
      /// [debug 下无法验证]
      onDidReceiveLocalNotification:
          (int id, String? title, String? body, String? payload) async {
        didReceiveLocalNotificationStream.add(
          ReceivedNotification(
            id: id,
            title: title,
            body: body,
            payload: Payload.fromString(payload),
          ),
        );
      },
      notificationCategories: darwinNotificationCategories,
    );

    /// 初始化 Linux 的消息通知配置
    final LinuxInitializationSettings initializationSettingsLinux =
        LinuxInitializationSettings(
      defaultActionName: 'Open notification',
      defaultIcon: AssetsLinuxIcon('icons/app_icon.png'),
    );

    /// 初始化消息通知配置 [四个系统的集合]
    final InitializationSettings initializationSettings =
        InitializationSettings(
      android: initializationSettingsAndroid,
      iOS: initializationSettingsDarwin,
      macOS: initializationSettingsDarwin,
      linux: initializationSettingsLinux,
    );

    /// 初始化消息通知 [最重要]
    await flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
      onDidReceiveNotificationResponse:
          (NotificationResponse notificationResponse) {
        switch (notificationResponse.notificationResponseType) {
          case NotificationResponseType.selectedNotification:
            selectNotificationStream.add(notificationResponse.payload);
            break;
          case NotificationResponseType.selectedNotificationAction:
            break;
        }
      },
      onDidReceiveBackgroundNotificationResponse: notificationTapBackground,
    );
  }

  /// 初始化权限
  void _initPermission() {
    /// 请求通知权限
    _requestPermissions();
  }

  /// 配置消息通知目录
  void _configSubjects() {
    /// 配置通知接收的回调（不走通知栏，直接应用内回调）
    _configureDidReceiveLocalNotificationSubject();

    /// 配置通知点击的回调
    _configureSelectNotificationSubject();
  }

  /// 请求通知权限 [重要]
  Future<void> _requestPermissions() async {
    if (Platform.isIOS || Platform.isMacOS) {
      await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<
              IOSFlutterLocalNotificationsPlugin>()
          ?.requestPermissions(
            alert: true,
            badge: true,
            sound: true,
          );
      await flutterLocalNotificationsPlugin
          .resolvePlatformSpecificImplementation<
              MacOSFlutterLocalNotificationsPlugin>()
          ?.requestPermissions(
            alert: true,
            badge: true,
            sound: true,
          );
    } else if (Platform.isAndroid) {
      flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>();
    }
  }

  /// 配置通知接收的回调 (没有进入通知栏，而是直接应用内回调)
  void _configureDidReceiveLocalNotificationSubject() {
    didReceiveLocalNotificationStream.stream
        .listen((ReceivedNotification receivedNotification) async {
      // await showDialog(
      //   context: context,
      //   builder: (BuildContext context) => Container()
      // );
    });
  }

  /// 配置通知点击的回调
  void _configureSelectNotificationSubject() {
    selectNotificationStream.stream.listen((String? payload) async {
      onNotificationClick.emit(this, Payload.fromString(payload));
    });
  }

  /// 应用处于后台时，点击通知栏内的消息通知的回调（不打开应用的情况下执行）
  /// 下面的 `vm:entry-point` 注释以确保它们不会被 Dart 编译器删除。
  @pragma('vm:entry-point')
  static void notificationTapBackground(
      NotificationResponse notificationResponse) {
    print("notificationTapBackground");
    // ignore: avoid_print
    // print('notification(${notificationResponse.id}) action tapped: '
    //     '${notificationResponse.actionId} with'
    //     ' payload: ${notificationResponse.payload}');
    // if (notificationResponse.input?.isNotEmpty ?? false) {
    //   // ignore: avoid_print
    //   print(
    //       'notification action tapped with input: ${notificationResponse.input}');
    // }
  }
}

/// 收到的消息
class ReceivedNotification {
  ReceivedNotification({
    required this.id,
    required this.title,
    required this.body,
    required this.payload,
  });

  final int id;
  final String? title;
  final String? body;
  final Payload? payload;
}

class Payload {
  Payload({
    required this.type,
    required this.message,
  });

  final PayloadType type;
  final String message;

  @override
  String toString() {
    return '{"type": "$type", "message": "$message"}';
  }

  /// 通过字符串构建 Payload
  factory Payload.fromString(String? payloadStr) {
    if (payloadStr == null) {
      return Payload(type: PayloadType.common, message: "");
    }
    final Map<String, dynamic> payloadMap = json.decode(payloadStr);
    return Payload(
      type: PayloadType.values.firstWhere(
        (PayloadType type) => type.toString() == payloadMap['type'],
      ),
      message: payloadMap['message'],
    );
  }
}

enum PayloadType {
  /// 通用
  common,

  /// 会诊通知
  consultation,

  /// TODO 其他类型在此补充
}
