import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:island/pods/audio.dart';
import 'package:island/pods/config.dart';
import 'package:island/pods/notification.dart';
import 'package:island/models/account.dart';
import 'package:island/pods/websocket.dart';
import 'package:island/talker.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:windows_notification/windows_notification.dart' as winty;
import 'package:windows_notification/notification_message.dart';

// Windows notification instance
winty.WindowsNotification? windowsNotification;

AppLifecycleState _appLifecycleState = AppLifecycleState.resumed;

void _onAppLifecycleChanged(AppLifecycleState state) {
  _appLifecycleState = state;
}

Future<void> initializeLocalNotifications() async {
  // Initialize Windows notification for Windows platform
  windowsNotification = winty.WindowsNotification(applicationId: "Solian");

  WidgetsBinding.instance.addObserver(
    LifecycleEventHandler(onAppLifecycleChanged: _onAppLifecycleChanged),
  );
}

class LifecycleEventHandler extends WidgetsBindingObserver {
  final void Function(AppLifecycleState) onAppLifecycleChanged;

  LifecycleEventHandler({required this.onAppLifecycleChanged});

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    onAppLifecycleChanged(state);
  }
}

StreamSubscription<WebSocketPacket> setupNotificationListener(
  BuildContext context,
  WidgetRef ref,
) {
  final settings = ref.watch(appSettingsProvider);
  final ws = ref.watch(websocketProvider);
  return ws.dataStream.listen((pkt) async {
    if (pkt.type == "notifications.new") {
      final notification = SnNotification.fromJson(pkt.data!);
      if (_appLifecycleState == AppLifecycleState.resumed) {
        talker.info(
          '[Notification] Showing in-app notification: ${notification.title}',
        );
        if (settings.notifyWithHaptic) {
          HapticFeedback.heavyImpact();
        }
        playNotificationSfx(ref);
        ref.read(notificationStateProvider.notifier).add(notification);
      } else {
        // App is in background, show Windows system notification
        talker.info(
          '[Notification] Showing Windows system notification: ${notification.title}',
        );

        if (windowsNotification != null) {
          final serverUrl = ref.read(serverUrlProvider);
          final pfp = notification.meta['pfp'] as String?;
          final img = notification.meta['images'] as List<dynamic>?;
          final actionUrl = notification.meta['action_uri'] as String?;

          // Download and cache images
          String? imagePath;
          String? largeImagePath;

          if (pfp != null) {
            try {
              final file = await DefaultCacheManager().getSingleFile(
                '$serverUrl/drive/files/$pfp',
              );
              imagePath = file.path;
            } catch (e) {
              talker.error('Failed to download pfp image: $e');
            }
          }

          if (img != null && img.isNotEmpty) {
            try {
              final file = await DefaultCacheManager().getSingleFile(
                '$serverUrl/drive/files/${img.firstOrNull}',
              );
              largeImagePath = file.path;
            } catch (e) {
              talker.error('Failed to download large image: $e');
            }
          }

          // Use Windows notification for Windows platform
          final notificationMessage = NotificationMessage.fromPluginTemplate(
            notification.id, // unique id
            notification.title,
            [
              notification.subtitle,
              notification.content,
            ].where((e) => e.isNotEmpty).join('\n'),
            group: notification.topic,
            image: imagePath,
            largeImage: largeImagePath,
            launch: actionUrl != null ? 'solian://$actionUrl' : null,
          );
          await windowsNotification!.showNotificationPluginTemplate(
            notificationMessage,
          );
        }
      }
    }
  });
}

Future<void> subscribePushNotification(
  Dio apiClient, {
  bool detailedErrors = false,
}) async {
  if (!kIsWeb && Platform.isLinux) {
    return;
  }
  await FirebaseMessaging.instance.requestPermission(
    alert: true,
    badge: true,
    sound: true,
  );

  String? deviceToken;
  if (kIsWeb) {
    deviceToken = await FirebaseMessaging.instance.getToken(
      vapidKey:
          "BFN2mkqyeI6oi4d2PAV4pfNyG3Jy0FBEblmmPrjmP0r5lHOPrxrcqLIWhM21R_cicF-j4Xhtr1kyDyDgJYRPLgU",
    );
  } else if (Platform.isAndroid) {
    deviceToken = await FirebaseMessaging.instance.getToken();
  } else if (Platform.isIOS) {
    deviceToken = await FirebaseMessaging.instance.getAPNSToken();
  }

  FirebaseMessaging.instance.onTokenRefresh
      .listen((fcmToken) {
        _putTokenToRemote(apiClient, fcmToken, 1);
      })
      .onError((err) {
        talker.error("Failed to get firebase cloud messaging push token: $err");
      });

  if (deviceToken != null) {
    _putTokenToRemote(
      apiClient,
      deviceToken,
      !kIsWeb && (Platform.isIOS || Platform.isMacOS) ? 0 : 1,
    );
  } else if (detailedErrors) {
    throw Exception("Failed to get device token for push notifications.");
  }
}

Future<void> _putTokenToRemote(
  Dio apiClient,
  String token,
  int provider,
) async {
  await apiClient.put(
    "/ring/notifications/subscription",
    data: {"provider": provider, "device_token": token},
  );
}
