import 'dart:developer';
import 'dart:io';

import 'package:croppy/croppy.dart';
import 'package:easy_localization/easy_localization.dart' hide TextDirection;
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.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_hooks/flutter_hooks.dart';
import 'package:go_router/go_router.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:image_picker_android/image_picker_android.dart';
import 'package:island/firebase_options.dart';
import 'package:island/pods/config.dart';
import 'package:island/pods/network.dart';
import 'package:island/pods/theme.dart';
import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:island/pods/userinfo.dart';
import 'package:island/pods/websocket.dart';
import 'package:island/route.dart';
import 'package:island/services/notify.dart';
import 'package:island/services/timezone.dart';
import 'package:island/widgets/alert.dart';
import 'package:island/widgets/app_scaffold.dart';
import 'package:relative_time/relative_time.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_picker_platform_interface/image_picker_platform_interface.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:flutter_langdetect/flutter_langdetect.dart' as langdetect;

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  log('Handling a background message: ${message.messageId}');
}

void main() async {
  final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
  if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
    log(
      "[SplashScreen] Keeping the flash screen to loading other resources...",
    );
    FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
  }

  if (kIsWeb) {
    GoRouter.optionURLReflectsImperativeAPIs = true;
  }

  try {
    await langdetect.initLangDetect();
    await EasyLocalization.ensureInitialized();

    if (kIsWeb || !Platform.isLinux) {
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      );
      FirebaseMessaging.onBackgroundMessage(
        _firebaseMessagingBackgroundHandler,
      );
      // Although previous if case checked this. Still check is web or not
      // Otherwise the web platform will broke due to there is no Platform api on the web
      // Skip crashlytics setup on debug mode to prevent unexpected report to firebase
      if ((kIsWeb || !Platform.isWindows) && !kDebugMode) {
        FlutterError.onError =
            FirebaseCrashlytics.instance.recordFlutterFatalError;
        PlatformDispatcher.instance.onError = (error, stack) {
          FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
          return true;
        };
      }
    }

    log("[SplashScreen] Firebase is ready!");
  } catch (err) {
    showErrorAlert(err);
  }

  try {
    log("[SplashScreen] Loading timezone database...");
    await initializeTzdb();
    log("[SplashScreen] Time zone database was loaded!");
  } catch (err) {
    log("[SplashScreen] Failed to load timezone database... $err");
  }

  final prefs = await SharedPreferences.getInstance();

  if (!kIsWeb && (Platform.isMacOS || Platform.isLinux || Platform.isWindows)) {
    doWhenWindowReady(() {
      const defaultSize = Size(360, 640);

      // Get saved window size from preferences
      final savedSizeString = prefs.getString(kAppWindowSize);
      Size initialSize = defaultSize;

      if (savedSizeString != null) {
        try {
          final parts = savedSizeString.split(',');
          if (parts.length == 2) {
            final width = double.parse(parts[0]);
            final height = double.parse(parts[1]);
            initialSize = Size(width, height);
          }
        } catch (e) {
          log("[SplashScreen] Failed to parse saved window size: $e");
          initialSize = defaultSize;
        }
      }

      appWindow.minSize = defaultSize;
      appWindow.size = initialSize;
      appWindow.alignment = Alignment.center;
      appWindow.show();
      log(
        "[SplashScreen] Desktop window is ready with size: ${initialSize.width}x${initialSize.height}",
      );
    });
  }

  if (!kIsWeb && Platform.isAndroid) {
    final ImagePickerPlatform imagePickerImplementation =
        ImagePickerPlatform.instance;
    if (imagePickerImplementation is ImagePickerAndroid) {
      imagePickerImplementation.useAndroidPhotoPicker = true;
    }
    log("[SplashScreen] Android image picker is ready!");
  }

  if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
    FlutterNativeSplash.remove();
    log("[SplashScreen] Now hiding the splash screen...");
  }

  runApp(
    ProviderScope(
      overrides: [sharedPreferencesProvider.overrideWithValue(prefs)],
      child: Directionality(
        textDirection: TextDirection.ltr,
        child: EasyLocalization(
          supportedLocales: [
            Locale('en', 'US'),
            Locale('zh', 'CN'),
            Locale('zh', 'TW'),
          ],
          path: 'assets/i18n',
          fallbackLocale: Locale('en', 'US'),
          useFallbackTranslations: true,
          child: IslandApp(),
        ),
      ),
    ),
  );
}

// Router will be provided through Riverpod

final globalOverlay = GlobalKey<OverlayState>();

class IslandApp extends HookConsumerWidget {
  const IslandApp({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final theme = ref.watch(themeProvider);

    void handleMessage(RemoteMessage notification) {
      if (notification.data['action_uri'] != null) {
        var uri = notification.data['action_uri'] as String;
        if (uri.startsWith('/')) {
          // In-app routes
          final router = ref.read(routerProvider);
          router.go(notification.data['action_uri']);
        } else {
          // External links
          launchUrlString(uri);
        }
      }
    }

    useEffect(() {
      if (!kIsWeb && Platform.isLinux) {
        return null;
      }
      const channel = MethodChannel('dev.solsynth.solian/notifications');

      Future<void> handleInitialLink() async {
        final String? link = await channel.invokeMethod('initialLink');
        if (link != null) {
          final router = ref.read(routerProvider);
          router.go(link);
        }
      }

      if (!kIsWeb && Platform.isAndroid) {
        handleInitialLink();
      }

      channel.setMethodCallHandler((call) async {
        if (call.method == 'newLink') {
          final String link = call.arguments;
          final router = ref.read(routerProvider);
          router.go(link);
        }
      });

      // When the app is opened from a terminated state.
      FirebaseMessaging.instance.getInitialMessage().then((message) {
        if (message != null) {
          handleMessage(message);
        }
      });

      // When the app is in the background and opened.
      final onMessageOpenedAppSubscription = FirebaseMessaging
          .onMessageOpenedApp
          .listen(handleMessage);

      // When the app is in the foreground.
      final onMessageSubscription = FirebaseMessaging.onMessage.listen((
        message,
      ) {
        log('Foreground message received: ${message.messageId}');
        handleMessage(message);
      });

      return () {
        onMessageOpenedAppSubscription.cancel();
        onMessageSubscription.cancel();
      };
    }, []);

    useEffect(() {
      // Load userinfo
      final userNotifier = ref.read(userInfoProvider.notifier);
      ref.listen(websocketStateProvider, (_, state) {
        log('[WebSocket] $state');
      });
      Future(() {
        userNotifier.fetchUser().then((_) {
          final user = ref.watch(userInfoProvider);
          if (user.value != null) {
            final apiClient = ref.read(apiClientProvider);
            subscribePushNotification(apiClient);
            final wsNotifier = ref.read(websocketStateProvider.notifier);
            wsNotifier.connect();
          }
        });
      });
      return null;
    }, []);

    final router = ref.watch(routerProvider);

    return MaterialApp.router(
      theme: theme?.light,
      darkTheme: theme?.dark,
      themeMode: ThemeMode.system,
      routerConfig: router,
      supportedLocales: context.supportedLocales,
      localizationsDelegates: [
        ...context.localizationDelegates,
        CroppyLocalizations.delegate,
        RelativeTimeLocalizations.delegate,
      ],
      locale: context.locale,
      builder: (context, child) {
        return Overlay(
          key: globalOverlay,
          initialEntries: [
            OverlayEntry(
              builder:
                  (_) =>
                      WindowScaffold(child: child ?? const SizedBox.shrink()),
            ),
          ],
        );
      },
    );
  }
}
