content: import 'dart:async';
  
  import 'package:flutter/foundation.dart';
  import 'package:flutter/material.dart';
  
  import 'package:collection/collection.dart';
  import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
  import 'package:go_router/go_router.dart';
  import 'package:matrix/matrix.dart';
  import 'package:universal_html/html.dart' as html;
  import 'package:url_launcher/url_launcher_string.dart';
  
  import 'package:fluffychat/config/app_config.dart';
  import 'package:fluffychat/l10n/l10n.dart';
  import 'package:fluffychat/pages/homeserver_picker/homeserver_picker_view.dart';
  import 'package:fluffychat/utils/file_selector.dart';
  import 'package:fluffychat/utils/platform_infos.dart';
  import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
  import 'package:fluffychat/widgets/matrix.dart';
  import '../../utils/localized_exception_extension.dart';
  
  import 'package:fluffychat/utils/tor_stub.dart'
      if (dart.library.html) 'package:tor_detector_web/tor_detector_web.dart';
  
  class HomeserverPicker extends StatefulWidget {
    final bool addMultiAccount;
    const HomeserverPicker({required this.addMultiAccount, super.key});
  
    @override
    HomeserverPickerController createState() => HomeserverPickerController();
  }
  
  class HomeserverPickerController extends State<HomeserverPicker> {
    bool isLoading = false;
  
    final TextEditingController homeserverController = TextEditingController(
      text: AppConfig.defaultHomeserver,
    );
  
    String? error;
  
    bool isTorBrowser = false;
  
    Future<void> _checkTorBrowser() async {
      if (!kIsWeb) return;
  
      final isTor = await TorBrowserDetector.isTorBrowser;
      isTorBrowser = isTor;
    }
  
    /// Starts an analysis of the given homeserver. It uses the current domain and
    /// makes sure that it is prefixed with https. Then it searches for the
    /// well-known information and forwards to the login page depending on the
    /// login type.
    Future<void> checkHomeserverAction({bool legacyPasswordLogin = false}) async {
      final homeserverInput =
          homeserverController.text.trim().toLowerCase().replaceAll(' ', '-');
  
      if (homeserverInput.isEmpty) {
        final client = await Matrix.of(context).getLoginClient();
        setState(() {
          error = loginFlows = null;
          isLoading = false;
          client.homeserver = null;
        });
        return;
      }
      setState(() {
        error = loginFlows = null;
        isLoading = true;
      });
  
      final l10n = L10n.of(context);
  
      try {
        var homeserver = Uri.parse(homeserverInput);
        if (homeserver.scheme.isEmpty) {
          homeserver = Uri.https(homeserverInput, '');
        }
        final client = await Matrix.of(context).getLoginClient();
        final (_, _, loginFlows) = await client.checkHomeserver(homeserver);
        this.loginFlows = loginFlows;
        if (supportsSso && !legacyPasswordLogin) {
          if (!PlatformInfos.isMobile) {
            final consent = await showOkCancelAlertDialog(
              context: context,
              title: l10n.appWantsToUseForLogin(homeserverInput),
              message: l10n.appWantsToUseForLoginDescription,
              okLabel: l10n.continueText,
            );
            if (consent != OkCancelResult.ok) return;
          }
          return ssoLoginAction();
        }
        context.push(
          '${GoRouter.of(context).routeInformationProvider.value.uri.path}/login',
          extra: client,
        );
      } catch (e) {
        setState(
          () => error = (e).toLocalizedString(
            context,
            ExceptionContext.checkHomeserver,
          ),
        );
      } finally {
        if (mounted) {
          setState(() => isLoading = false);
        }
      }
    }
  
    List<LoginFlow>? loginFlows;
  
    bool _supportsFlow(String flowType) =>
        loginFlows?.any((flow) => flow.type == flowType) ?? false;
  
    bool get supportsSso => _supportsFlow('m.login.sso');
  
    bool isDefaultPlatform =
        (PlatformInfos.isMobile || PlatformInfos.isWeb || PlatformInfos.isMacOS);
  
    bool get supportsPasswordLogin => _supportsFlow('m.login.password');
  
    void ssoLoginAction() async {
      final redirectUrl = kIsWeb
          ? Uri.parse(html.window.location.href)
              .resolveUri(
                Uri(pathSegments: ['auth.html']),
              )
              .toString()
          : isDefaultPlatform
              ? '${AppConfig.appOpenUrlScheme.toLowerCase()}://login'
              : 'http://localhost:3001//login';
      final client = await Matrix.of(context).getLoginClient();
      final url = client.homeserver!.replace(
        path: '/_matrix/client/v3/login/sso/redirect',
        queryParameters: {'redirectUrl': redirectUrl},
      );
  
      final urlScheme = isDefaultPlatform
          ? Uri.parse(redirectUrl).scheme
          : "http://localhost:3001";
      final result = await FlutterWebAuth2.authenticate(
        url: url.toString(),
        callbackUrlScheme: urlScheme,
        options: const FlutterWebAuth2Options(),
      );
      final token = Uri.parse(result).queryParameters['loginToken'];
      if (token?.isEmpty ?? false) return;
  
      setState(() {
        error = null;
        isLoading = true;
      });
      try {
        await client.login(
          LoginType.mLoginToken,
          token: token,
          initialDeviceDisplayName: PlatformInfos.clientName,
        );
      } catch (e) {
        setState(() {
          error = e.toLocalizedString(context);
        });
      } finally {
        if (mounted) {
          setState(() {
            isLoading = false;
          });
        }
      }
    }
  
    @override
    void initState() {
      _checkTorBrowser();
      super.initState();
    }
  
    @override
    Widget build(BuildContext context) => HomeserverPickerView(this);
  
    Future<void> restoreBackup() async {
      final picked = await selectFiles(context);
      final file = picked.firstOrNull;
      if (file == null) return;
      setState(() {
        error = null;
        isLoading = true;
      });
      try {
        final client = await Matrix.of(context).getLoginClient();
        await client.importDump(String.fromCharCodes(await file.readAsBytes()));
        Matrix.of(context).initMatrix();
      } catch (e) {
        setState(() {
          error = e.toLocalizedString(context);
        });
      } finally {
        if (mounted) {
          setState(() {
            isLoading = false;
          });
        }
      }
    }
  
    void onMoreAction(MoreLoginActions action) {
      switch (action) {
        case MoreLoginActions.importBackup:
          restoreBackup();
        case MoreLoginActions.privacy:
          launchUrlString(AppConfig.privacyUrl);
        case MoreLoginActions.about:
          PlatformInfos.showDialog(context);
      }
    }
  }
  
  enum MoreLoginActions { importBackup, privacy, about }
  
  class IdentityProvider {
    final String? id;
    final String? name;
    final String? icon;
    final String? brand;
  
    IdentityProvider({this.id, this.name, this.icon, this.brand});
  
    factory IdentityProvider.fromJson(Map<String, dynamic> json) =>
        IdentityProvider(
          id: json['id'],
          name: json['name'],
          icon: json['icon'],
          brand: json['brand'],
        );
  }
  