content: import 'dart:convert';
  import 'dart:ui';
  
  import 'package:flutter_secure_storage/flutter_secure_storage.dart';
  import 'package:matrix/matrix.dart';
  
  import 'package:fluffychat/config/app_config.dart';
  import 'package:fluffychat/l10n/l10n.dart';
  import 'package:fluffychat/utils/client_manager.dart';
  import 'package:fluffychat/utils/platform_infos.dart';
  
  class SessionBackup {
    final String? olmAccount;
    final String accessToken;
    final String userId;
    final String homeserver;
    final String? deviceId;
    final String? deviceName;
  
    const SessionBackup({
      required this.olmAccount,
      required this.accessToken,
      required this.userId,
      required this.homeserver,
      required this.deviceId,
      this.deviceName,
    });
  
    factory SessionBackup.fromJsonString(String json) =>
        SessionBackup.fromJson(jsonDecode(json));
  
    factory SessionBackup.fromJson(Map<String, dynamic> json) => SessionBackup(
          olmAccount: json['olm_account'],
          accessToken: json['access_token'],
          userId: json['user_id'],
          homeserver: json['homeserver'],
          deviceId: json['device_id'],
          deviceName: json['device_name'],
        );
  
    Map<String, dynamic> toJson() => {
          'olm_account': olmAccount,
          'access_token': accessToken,
          'user_id': userId,
          'homeserver': homeserver,
          'device_id': deviceId,
          if (deviceName != null) 'device_name': deviceName,
        };
  
    @override
    String toString() => jsonEncode(toJson());
  }
  
  extension InitWithRestoreExtension on Client {
    static Future<void> deleteSessionBackup(String clientName) async {
      final storage = PlatformInfos.isMobile || PlatformInfos.isLinux
          ? const FlutterSecureStorage()
          : null;
      await storage?.delete(
        key: '${AppConfig.applicationName}_session_backup_$clientName',
      );
    }
  
    Future<void> initWithRestore({void Function()? onMigration}) async {
      final storageKey =
          '${AppConfig.applicationName}_session_backup_$clientName';
      final storage = PlatformInfos.isMobile || PlatformInfos.isLinux
          ? const FlutterSecureStorage()
          : null;
  
      try {
        await init(
          onInitStateChanged: (state) {
            if (state == InitState.migratingDatabase) onMigration?.call();
          },
          waitForFirstSync: false,
          waitUntilLoadCompletedLoaded: false,
        );
        if (isLogged()) {
          final accessToken = this.accessToken;
          final homeserver = this.homeserver?.toString();
          final deviceId = deviceID;
          final userId = userID;
          final hasBackup = accessToken != null &&
              homeserver != null &&
              deviceId != null &&
              userId != null;
          assert(hasBackup);
          if (hasBackup) {
            Logs().v('Store session in backup');
            storage?.write(
              key: storageKey,
              value: SessionBackup(
                olmAccount: encryption?.pickledOlmAccount,
                accessToken: accessToken,
                deviceId: deviceId,
                homeserver: homeserver,
                deviceName: deviceName,
                userId: userId,
              ).toString(),
            );
          }
        }
      } catch (e, s) {
        Logs().wtf('Client init failed!', e, s);
        final l10n = await lookupL10n(PlatformDispatcher.instance.locale);
        final sessionBackupString = await storage?.read(key: storageKey);
        if (sessionBackupString == null) {
          ClientManager.sendInitNotification(
            l10n.initAppError,
            l10n.sessionLostBody(AppConfig.newIssueUrl.toString(), e.toString()),
          );
          rethrow;
        }
  
        try {
          final sessionBackup = SessionBackup.fromJsonString(sessionBackupString);
          await init(
            newToken: sessionBackup.accessToken,
            newOlmAccount: sessionBackup.olmAccount,
            newDeviceID: sessionBackup.deviceId,
            newDeviceName: sessionBackup.deviceName,
            newHomeserver: Uri.tryParse(sessionBackup.homeserver),
            newUserID: sessionBackup.userId,
            waitForFirstSync: false,
            waitUntilLoadCompletedLoaded: false,
            onInitStateChanged: (state) {
              if (state == InitState.migratingDatabase) onMigration?.call();
            },
          );
          ClientManager.sendInitNotification(
            l10n.initAppError,
            l10n.restoreSessionBody(
              AppConfig.newIssueUrl.toString(),
              e.toString(),
            ),
          );
        } catch (e, s) {
          Logs().wtf('Restore client failed!', e, s);
          ClientManager.sendInitNotification(
            l10n.initAppError,
            l10n.sessionLostBody(AppConfig.newIssueUrl.toString(), e.toString()),
          );
          rethrow;
        }
      }
    }
  }
  