import 'dart:async';

import 'package:app_links/app_links.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_sharing_intent/model/sharing_file.dart' show SharedFile;
import 'package:provider/provider.dart';
import 'package:twonly/globals.dart';
import 'package:twonly/locator.dart';
import 'package:twonly/src/constants/keyvalue.keys.dart';
import 'package:twonly/src/constants/routes.keys.dart';
import 'package:twonly/src/database/tables/mediafiles.table.dart';
import 'package:twonly/src/localization/generated/app_localizations.dart';
import 'package:twonly/src/model/json/onboarding_state.model.dart';
import 'package:twonly/src/providers/routing.provider.dart';
import 'package:twonly/src/providers/settings.provider.dart';
import 'package:twonly/src/services/intent/links.intent.dart';
import 'package:twonly/src/utils/keyvalue.dart';
import 'package:twonly/src/utils/log.dart';
import 'package:twonly/src/utils/pow.dart';
import 'package:twonly/src/visual/components/app_outdated.comp.dart';
import 'package:twonly/src/visual/themes/dark.dart';
import 'package:twonly/src/visual/themes/light.dart';
import 'package:twonly/src/visual/views/critical_error.view.dart';
import 'package:twonly/src/visual/views/home.view.dart';
import 'package:twonly/src/visual/views/onboarding/onboarding.view.dart';
import 'package:twonly/src/visual/views/onboarding/register.view.dart';
import 'package:twonly/src/visual/views/onboarding/setup.view.dart';
import 'package:twonly/src/visual/views/recovery_from_secure_storage.view.dart';
import 'package:twonly/src/visual/views/unlock_twonly.view.dart';

class App extends StatefulWidget {
  const App({
    required this.storageError,
    required this.recoveryPossible,
    super.key,
  });
  final bool storageError;
  final bool recoveryPossible;
  @override
  State<App> createState() => _AppState();
}

class _AppState extends State<App> with WidgetsBindingObserver {
  bool _wasPaused = false;

  @override
  void initState() {
    super.initState();
    AppState.isAppInBackground = false;
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed) {
      if (_wasPaused) {
        AppState.isAppInBackground = false;
        twonlyDB.markUpdated();
        unawaited(apiService.connect());
      }
    } else if (state == AppLifecycleState.paused) {
      _wasPaused = true;
      AppState.isAppInBackground = true;
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return ListenableBuilder(
      listenable: context.read<SettingsChangeProvider>(),
      builder: (context, child) {
        const localizationsDelegates = [
          AppLocalizations.delegate,
          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
        ];

        const supportedLocales = [
          Locale('en', ''),
          Locale('de', ''),
        ];

        final settings = context.watch<SettingsChangeProvider>();

        if (widget.storageError) {
          return MaterialApp(
            localizationsDelegates: localizationsDelegates,
            debugShowCheckedModeBanner: false,
            supportedLocales: supportedLocales,
            title: 'twonly',
            theme: getLightTheme(settings.primaryColor),
            darkTheme: getDarkTheme(settings.primaryColor),
            themeMode: settings.themeMode,
            home: const CriticalErrorView(),
          );
        }

        if (widget.recoveryPossible) {
          return MaterialApp(
            localizationsDelegates: localizationsDelegates,
            debugShowCheckedModeBanner: false,
            supportedLocales: supportedLocales,
            title: 'twonly',
            theme: getLightTheme(settings.primaryColor),
            darkTheme: getDarkTheme(settings.primaryColor),
            themeMode: settings.themeMode,
            home: const RecoveryView(),
          );
        }

        return MaterialApp.router(
          routerConfig: routerProvider,
          localizationsDelegates: localizationsDelegates,
          debugShowCheckedModeBanner: false,
          supportedLocales: supportedLocales,
          title: 'twonly',
          theme: getLightTheme(settings.primaryColor),
          darkTheme: getDarkTheme(settings.primaryColor),
          themeMode: settings.themeMode,
        );
      },
    );
  }
}

class AppMainWidget extends StatefulWidget {
  const AppMainWidget({
    required this.initialPage,
    super.key,
  });
  final int initialPage;
  @override
  State<AppMainWidget> createState() => _AppMainWidgetState();
}

class _AppMainWidgetState extends State<AppMainWidget> {
  bool _showOnboarding = true;
  bool _isLoaded = false;
  bool _isTwonlyLocked = true;
  bool _wasLogged = true;
  late int _initialPage;

  StreamSubscription<Uri>? _deepLinkSub;
  StreamSubscription<List<SharedFile>>? _intentStreamSub;
  StreamSubscription<String>? _emailTokenSub;

  (Future<int>?, bool) _proofOfWork = (null, false);

  @override
  void initState() {
    super.initState();
    _initialPage = widget.initialPage;
    Log.info('AppWidgetState: initState started');
    initAsync();

    void handleShareLink(Uri uri) {
      HomeViewState.pendingSharedLink = uri;
      routerProvider.go(Routes.home);
      HomeViewState.streamHomeViewPageIndex.add(1);
      HomeViewState.streamSharedLink.add(uri);
    }

    // Subscribe to all events (initial link and further)
    _deepLinkSub = AppLinks().uriLinkStream.listen((uri) async {
      if (!mounted) return;
      Log.info('Got link via app links: ${uri.scheme}');
      if (!await handleIntentUrl(context, uri)) {
        if (uri.scheme.startsWith('http')) {
          handleShareLink(uri);
        }
      }
    });

    void handleShareMedia(String path, MediaType type) {
      HomeViewState.pendingSharedMedia = (path, type);
      routerProvider.go(Routes.home);
      HomeViewState.streamHomeViewPageIndex.add(0);
      HomeViewState.streamSharedMedia.add((path, type));
    }

    _intentStreamSub = initIntentStreams(
      context,
      handleShareLink,
      handleShareMedia,
    );
  }

  Future<void> initAsync() async {
    Log.info('AppWidgetState: initAsync started');
    final onboardingState = await KeyValueStore.getModel<OnboardingState>(
      KeyValueKeys.onboardingState,
    );
    _showOnboarding = !onboardingState.hasOnboardingFinished;
    if (userService.isUserCreated) {
      if (_initialPage != 0) {
        final count = await twonlyDB.contactsDao.getContactsCount();
        if (count == 0) {
          _initialPage = 0;
        }
      }
      try {
        unawaited(FirebaseMessaging.instance.requestPermission());
      } catch (e) {
        Log.error(e);
      }
      if (_isTwonlyLocked) {
        // do not change in case twonly was already unlocked at some point
        _isTwonlyLocked = userService.currentUser.screenLockEnabled;
      }
    } else {
      // This means the user is in the onboarding screen, so start with the Proof of Work.

      final (proof, disabled) = await apiService.getProofOfWork();
      if (proof != null) {
        Log.info('Starting with proof of work calculation.');
        _proofOfWork = (
          calculatePoW(proof.prefix, proof.difficulty.toInt()),
          false,
        );
      } else {
        _proofOfWork = (null, disabled);
      }

      if (onboardingState.hasStartedPasswordlessRecovery ||
          onboardingState.emailRecoveryRequested) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          routerProvider.push(Routes.recoverPasswordless);
        });
      }
    }

    setState(() {
      _isLoaded = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (!_wasLogged) {
      Log.info('AppWidgetState: build started (_isLoaded: $_isLoaded)');
      if (_isLoaded) {
        _wasLogged = true;
      }
    }
    if (!_isLoaded) {
      return Center(child: Container());
    }

    late Widget child;

    if (userService.isUserCreated) {
      if (_isTwonlyLocked) {
        child = UnlockTwonlyView(
          callbackOnSuccess: () => setState(() {
            _isTwonlyLocked = false;
          }),
        );
      } else if (!userService.currentUser.skipSetupPages &&
          userService.currentUser.currentSetupPage != null) {
        // This will only be shown in case the user have not skipped
        child = SetupView(
          onUpdate: () => setState(() {
            // userService.currentUser has updated...
          }),
        );
      } else {
        child = HomeView(
          initialPage: _initialPage,
        );
      }
    } else if (_showOnboarding) {
      child = OnboardingView(
        callbackOnSuccess: () async {
          await KeyValueStore.update<OnboardingState>(
            key: KeyValueKeys.onboardingState,
            update: (state) => state.hasOnboardingFinished = true,
          );
          if (mounted) setState(() => _showOnboarding = false);
        },
      );
    } else {
      child = RegisterView(
        callbackOnSuccess: initAsync,
        proofOfWork: _proofOfWork,
      );
    }

    return Stack(
      children: [
        child,
        const AppOutdatedComp(),
      ],
    );
  }

  @override
  void dispose() {
    _deepLinkSub?.cancel();
    _intentStreamSub?.cancel();
    _emailTokenSub?.cancel();
    super.dispose();
  }
}
