content: import 'dart:convert';
  import 'dart:ui';
  
  import 'package:flutter/material.dart';
  import 'package:flutter/services.dart';
  
  import 'package:matrix/encryption.dart';
  import 'package:matrix/matrix.dart';
  
  import 'package:fluffychat/l10n/l10n.dart';
  import 'package:fluffychat/widgets/adaptive_dialogs/adaptive_dialog_action.dart';
  import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
  import 'package:fluffychat/widgets/avatar.dart';
  import 'package:fluffychat/widgets/future_loading_dialog.dart';
  
  class KeyVerificationDialog extends StatefulWidget {
    Future<void> show(BuildContext context) => showAdaptiveDialog(
          context: context,
          builder: (context) => this,
          barrierDismissible: false,
        );
  
    final KeyVerification request;
  
    const KeyVerificationDialog({
      super.key,
      required this.request,
    });
  
    @override
    KeyVerificationPageState createState() => KeyVerificationPageState();
  }
  
  class KeyVerificationPageState extends State<KeyVerificationDialog> {
    void Function()? originalOnUpdate;
    late final List<dynamic> sasEmoji;
  
    @override
    void initState() {
      originalOnUpdate = widget.request.onUpdate;
      widget.request.onUpdate = () {
        originalOnUpdate?.call();
        setState(() {});
      };
      widget.request.client.getProfileFromUserId(widget.request.userId).then((p) {
        profile = p;
        setState(() {});
      });
      rootBundle.loadString('assets/sas-emoji.json').then((e) {
        sasEmoji = json.decode(e);
        setState(() {});
      });
      super.initState();
    }
  
    @override
    void dispose() {
      widget.request.onUpdate =
          originalOnUpdate; // don't want to get updates anymore
      if (![KeyVerificationState.error, KeyVerificationState.done]
          .contains(widget.request.state)) {
        widget.request.cancel('m.user');
      }
      super.dispose();
    }
  
    Profile? profile;
  
    Future<void> checkInput(String input) async {
      if (input.isEmpty) return;
  
      final valid = await showFutureLoadingDialog(
        context: context,
        future: () async {
          // make sure the loading spinner shows before we test the keys
          await Future.delayed(const Duration(milliseconds: 100));
          var valid = false;
          try {
            await widget.request.openSSSS(keyOrPassphrase: input);
            valid = true;
          } catch (_) {
            valid = false;
          }
          return valid;
        },
      );
      if (valid.error != null) {
        await showOkAlertDialog(
          useRootNavigator: false,
          context: context,
          title: L10n.of(context).incorrectPassphraseOrKey,
        );
      }
    }
  
    @override
    Widget build(BuildContext context) {
      final theme = Theme.of(context);
  
      User? user;
      final directChatId =
          widget.request.client.getDirectChatFromUserId(widget.request.userId);
      if (directChatId != null) {
        user = widget.request.client
            .getRoomById(directChatId)!
            .unsafeGetUserFromMemoryOrFallback(widget.request.userId);
      }
      final displayName =
          user?.calcDisplayname() ?? widget.request.userId.localpart!;
      var title = Text(L10n.of(context).verifyTitle);
      Widget body;
      final buttons = <Widget>[];
  
      switch (widget.request.state) {
        case KeyVerificationState.showQRSuccess:
        case KeyVerificationState.confirmQRScan:
          throw 'Not implemented';
        case KeyVerificationState.askSSSS:
          // prompt the user for their ssss passphrase / key
          final textEditingController = TextEditingController();
          String input;
          body = Container(
            margin: const EdgeInsets.only(left: 8.0, right: 8.0),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Text(
                  L10n.of(context).askSSSSSign,
                  style: const TextStyle(fontSize: 20),
                ),
                Container(height: 10),
                TextField(
                  controller: textEditingController,
                  autofocus: false,
                  autocorrect: false,
                  onSubmitted: (s) {
                    input = s;
                    checkInput(input);
                  },
                  minLines: 1,
                  maxLines: 1,
                  obscureText: true,
                  decoration: InputDecoration(
                    hintText: L10n.of(context).passphraseOrKey,
                    prefixStyle: TextStyle(color: theme.colorScheme.primary),
                    suffixStyle: TextStyle(color: theme.colorScheme.primary),
                    border: const OutlineInputBorder(),
                  ),
                ),
              ],
            ),
          );
          buttons.add(
            AdaptiveDialogAction(
              child: Text(
                L10n.of(context).submit,
              ),
              onPressed: () => checkInput(textEditingController.text),
            ),
          );
          buttons.add(
            AdaptiveDialogAction(
              child: Text(
                L10n.of(context).skip,
              ),
              onPressed: () => widget.request.openSSSS(skip: true),
            ),
          );
          break;
        case KeyVerificationState.askAccept:
          title = Text(L10n.of(context).newVerificationRequest);
          body = Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              const SizedBox(height: 16),
              Avatar(
                mxContent: user?.avatarUrl,
                name: displayName,
                size: Avatar.defaultSize * 2,
              ),
              const SizedBox(height: 16),
              Text(
                L10n.of(context).askVerificationRequest(displayName),
              ),
            ],
          );
          buttons.add(
            AdaptiveDialogAction(
              onPressed: () => widget.request
                  .rejectVerification()
                  .then((_) => Navigator.of(context, rootNavigator: false).pop()),
              child: Text(
                L10n.of(context).reject,
                style: TextStyle(color: theme.colorScheme.error),
              ),
            ),
          );
          buttons.add(
            AdaptiveDialogAction(
              onPressed: () => widget.request.acceptVerification(),
              child: Text(L10n.of(context).accept),
            ),
          );
          break;
        case KeyVerificationState.askChoice:
        case KeyVerificationState.waitingAccept:
          body = Center(
            child: Column(
              children: <Widget>[
                const SizedBox(height: 16),
                Stack(
                  alignment: Alignment.center,
                  children: [
                    Avatar(
                      mxContent: user?.avatarUrl,
                      name: displayName,
                    ),
                    const SizedBox(
                      width: Avatar.defaultSize + 2,
                      height: Avatar.defaultSize + 2,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    ),
                  ],
                ),
                const SizedBox(height: 16),
                Text(
                  L10n.of(context).waitingPartnerAcceptRequest,
                  textAlign: TextAlign.center,
                ),
              ],
            ),
          );
          buttons.add(
            AdaptiveDialogAction(
              onPressed: () => widget.request.cancel(),
              child: Text(L10n.of(context).cancel),
            ),
          );
  
          break;
        case KeyVerificationState.askSas:
          TextSpan compareWidget;
          // maybe add a button to switch between the two and only determine default
          // view for if "emoji" is a present sasType or not?
  
          if (widget.request.sasTypes.contains('emoji')) {
            title = Text(
              L10n.of(context).compareEmojiMatch,
              maxLines: 1,
              style: const TextStyle(fontSize: 16),
            );
            compareWidget = TextSpan(
              children: widget.request.sasEmojis
                  .map((e) => WidgetSpan(child: _Emoji(e, sasEmoji)))
                  .toList(),
            );
          } else {
            title = Text(L10n.of(context).compareNumbersMatch);
            final numbers = widget.request.sasNumbers;
            final numbstr = '${numbers[0]}-${numbers[1]}-${numbers[2]}';
            compareWidget =
                TextSpan(text: numbstr, style: const TextStyle(fontSize: 40));
          }
          body = Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Text.rich(
                compareWidget,
                textAlign: TextAlign.center,
              ),
            ],
          );
          buttons.add(
            AdaptiveDialogAction(
              onPressed: () => widget.request.rejectSas(),
              child: Text(
                L10n.of(context).theyDontMatch,
                style: TextStyle(color: theme.colorScheme.error),
              ),
            ),
          );
          buttons.add(
            AdaptiveDialogAction(
              onPressed: () => widget.request.acceptSas(),
              child: Text(L10n.of(context).theyMatch),
            ),
          );
          break;
        case KeyVerificationState.waitingSas:
          final acceptText = widget.request.sasTypes.contains('emoji')
              ? L10n.of(context).waitingPartnerEmoji
              : L10n.of(context).waitingPartnerNumbers;
          body = Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              const SizedBox(height: 16),
              const CircularProgressIndicator.adaptive(strokeWidth: 2),
              const SizedBox(height: 16),
              Text(
                acceptText,
                textAlign: TextAlign.center,
              ),
            ],
          );
          break;
        case KeyVerificationState.done:
          title = Text(L10n.of(context).verifySuccess);
          body = const Padding(
            padding: EdgeInsets.all(16.0),
            child: Icon(
              Icons.verified_outlined,
              color: Colors.green,
              size: 128.0,
            ),
          );
          buttons.add(
            AdaptiveDialogAction(
              child: Text(
                L10n.of(context).close,
              ),
              onPressed: () => Navigator.of(context, rootNavigator: false).pop(),
            ),
          );
          break;
        case KeyVerificationState.error:
          title = const Text('');
          body = Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              const SizedBox(height: 16),
              Icon(Icons.cancel, color: theme.colorScheme.error, size: 64.0),
              const SizedBox(height: 16),
              // TODO: Add better error UI to user
              Text(
                'Error ${widget.request.canceledCode}: ${widget.request.canceledReason}',
                textAlign: TextAlign.center,
              ),
            ],
          );
          buttons.add(
            AdaptiveDialogAction(
              child: Text(
                L10n.of(context).close,
              ),
              onPressed: () => Navigator.of(context, rootNavigator: false).pop(),
            ),
          );
          break;
      }
  
      return AlertDialog.adaptive(
        title: title,
        content: SizedBox(
          height: 256,
          width: 256,
          child: ListView(
            children: [body],
          ),
        ),
        actions: buttons,
      );
    }
  }
  
  class _Emoji extends StatelessWidget {
    final KeyVerificationEmoji emoji;
    final List<dynamic>? sasEmoji;
  
    const _Emoji(this.emoji, this.sasEmoji);
  
    String getLocalizedName() {
      final sasEmoji = this.sasEmoji;
      if (sasEmoji == null) {
        // asset is still being loaded
        return emoji.name;
      }
      final translations = Map<String, String?>.from(
        sasEmoji[emoji.number]['translated_descriptions'],
      );
      translations['en'] = emoji.name;
      for (final locale in PlatformDispatcher.instance.locales) {
        final wantLocaleParts = locale.toString().split('_');
        final wantLanguage = wantLocaleParts.removeAt(0);
        for (final haveLocale in translations.keys) {
          final haveLocaleParts = haveLocale.split('_');
          final haveLanguage = haveLocaleParts.removeAt(0);
          if (haveLanguage == wantLanguage &&
              (Set.from(haveLocaleParts)..removeAll(wantLocaleParts)).isEmpty &&
              (translations[haveLocale]?.isNotEmpty ?? false)) {
            return translations[haveLocale]!;
          }
        }
      }
      return emoji.name;
    }
  
    @override
    Widget build(BuildContext context) {
      return Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text(emoji.emoji, style: const TextStyle(fontSize: 50)),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 4.0),
            child: Text(getLocalizedName()),
          ),
          const SizedBox(height: 10, width: 5),
        ],
      );
    }
  }
  