import 'package:flutter/material.dart';
import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart';
import 'package:pyramid/core/theme.dart';

/// Ob Cross-Signing/Key-Backup fehlt oder nicht entsperrt ist — wenn ja, würde
/// ein Logout den Zugriff auf ältere verschlüsselte Nachrichten kosten.
Future<bool> isKeyBackupMissing(Client client) async {
  final enc = client.encryption;
  if (enc == null) return true;
  if (!enc.crossSigning.enabled) return true;
  return !(await enc.keyManager.isCached().catchError((_) => false));
}

Future<void> showBootstrapDialog(
  BuildContext context,
  Client client, {
  bool force = false,
}) async {
  if (client.encryption == null) return;
  if (!force) {
    final enc = client.encryption!;
    final cached = await enc.keyManager.isCached().catchError((_) => false);
    if (cached && enc.crossSigning.enabled) return;
  }
  if (!context.mounted) return;
  await showDialog<bool>(
    context: context,
    barrierDismissible: false,
    builder: (_) => _BootstrapDialog(client: client),
  );
}

class _BootstrapDialog extends StatefulWidget {
  final Client client;
  const _BootstrapDialog({required this.client});

  @override
  State<_BootstrapDialog> createState() => _BootstrapDialogState();
}

class _BootstrapDialogState extends State<_BootstrapDialog> {
  Bootstrap? _bootstrap;
  final _keyCtrl = TextEditingController();
  bool _keyLoading = false;
  String? _keyError;
  bool _wipe = false;

  @override
  void initState() {
    super.initState();
    _start();
  }

  @override
  void dispose() {
    _keyCtrl.dispose();
    super.dispose();
  }

  Future<void> _start() async {
    final client = widget.client;
    await client.roomsLoading;
    await client.accountDataLoading;
    await client.userDeviceKeysLoading;
    while (client.prevBatch == null) {
      await client.onSyncStatus.stream.first;
    }
    if (!mounted) return;
    setState(() {
      _bootstrap = client.encryption!.bootstrap(
        onUpdate: (_) {
          if (mounted) setState(() {});
        },
      );
    });
  }

  void _autoAdvance(Bootstrap bs) {
    switch (bs.state) {
      case BootstrapState.askWipeSsss:
        WidgetsBinding.instance
            .addPostFrameCallback((_) => bs.wipeSsss(_wipe));
      case BootstrapState.askBadSsss:
        WidgetsBinding.instance
            .addPostFrameCallback((_) => bs.ignoreBadSecrets(true));
      case BootstrapState.askUseExistingSsss:
        WidgetsBinding.instance
            .addPostFrameCallback((_) => bs.useExistingSsss(!_wipe));
      case BootstrapState.askUnlockSsss:
        // Handled by UI if oldSsssKeys exist, otherwise skip
        WidgetsBinding.instance
            .addPostFrameCallback((_) => bs.unlockedSsss());
      case BootstrapState.askNewSsss:
        WidgetsBinding.instance.addPostFrameCallback((_) => bs.newSsss());
      case BootstrapState.askWipeCrossSigning:
        WidgetsBinding.instance
            .addPostFrameCallback((_) => bs.wipeCrossSigning(_wipe));
      case BootstrapState.askSetupCrossSigning:
        WidgetsBinding.instance.addPostFrameCallback(
          (_) => bs.askSetupCrossSigning(
            setupMasterKey: true,
            setupSelfSigningKey: true,
            setupUserSigningKey: true,
          ),
        );
      case BootstrapState.askWipeOnlineKeyBackup:
        WidgetsBinding.instance
            .addPostFrameCallback((_) => bs.wipeOnlineKeyBackup(_wipe));
      case BootstrapState.askSetupOnlineKeyBackup:
        WidgetsBinding.instance
            .addPostFrameCallback((_) => bs.askSetupOnlineKeyBackup(true));
      default:
        break;
    }
  }

  Future<void> _unlock() async {
    final bs = _bootstrap;
    if (bs == null || bs.newSsssKey == null) return;
    final key = _keyCtrl.text.trim();
    if (key.isEmpty) {
      setState(() => _keyError = 'Bitte Wiederherstellungsschlüssel eingeben.');
      return;
    }
    setState(() {
      _keyLoading = true;
      _keyError = null;
    });
    try {
      await bs.newSsssKey!.unlock(keyOrPassphrase: key);
      Logs().d('[Bootstrap] SSSS key unlocked');
      await bs.openExistingSsss();
      Logs().d('[Bootstrap] SSSS opened, secrets cached');
      if (bs.encryption.crossSigning.enabled) {
        await widget.client.encryption!.crossSigning.selfSign(recoveryKey: key);
        Logs().d('[Bootstrap] Cross-signing self-signed');
      }
    } on InvalidPassphraseException catch (_) {
      setState(
        () => _keyError = 'Falscher Schlüssel. Bitte nochmal prüfen.',
      );
    } on FormatException catch (_) {
      setState(() => _keyError = 'Ungültiges Format. Prüfe deinen Schlüssel.');
    } catch (e) {
      setState(() => _keyError = e.toString().split('\n').first);
    } finally {
      if (mounted) setState(() => _keyLoading = false);
    }
  }

  Future<void> _close({required bool success}) async {
    if (success) {
      // Download all megolm session keys from backup — bypasses
      // _requestedSessionIds deduplication so previously failed decryptions
      // get a second chance.
      widget.client.encryption?.keyManager
          .loadAllKeys()
          .catchError((e) => Logs().e('[Bootstrap] loadAllKeys failed', e));
    }
    if (mounted) Navigator.of(context).pop(success);
  }

  @override
  Widget build(BuildContext context) {
    final pt = PyramidTheme.of(context);
    final bs = _bootstrap;

    // Waiting for bootstrap to initialise
    if (bs == null || bs.state == BootstrapState.loading) {
      return _Shell(
        pt: pt,
        title: 'Verschlüsselung einrichten',
        onClose: () => _close(success: false),
        child: const Center(
          child: Padding(
            padding: EdgeInsets.all(32),
            child: CircularProgressIndicator.adaptive(),
          ),
        ),
      );
    }

    // User must enter recovery key
    if (bs.state == BootstrapState.openExistingSsss) {
      return _Shell(
        pt: pt,
        title: 'Nachrichten entschlüsseln',
        onClose: () => _close(success: false),
        child: _KeyInputBody(
          pt: pt,
          ctrl: _keyCtrl,
          loading: _keyLoading,
          error: _keyError,
          onUnlock: _unlock,
          onWipe: () {
            setState(() {
              _wipe = true;
              _start();
            });
          },
        ),
      );
    }

    // Success — all done
    if (bs.state == BootstrapState.done) {
      return _Shell(
        pt: pt,
        title: 'Einrichtung abgeschlossen',
        onClose: null,
        child: _DoneBody(
          pt: pt,
          onClose: () => _close(success: true),
        ),
      );
    }

    // Error
    if (bs.state == BootstrapState.error) {
      return _Shell(
        pt: pt,
        title: 'Fehler',
        onClose: () => _close(success: false),
        child: _ErrorBody(
          pt: pt,
          onClose: () => _close(success: false),
        ),
      );
    }

    // Auto-advance all other (non-interactive) states
    _autoAdvance(bs);
    return _Shell(
      pt: pt,
      title: 'Verschlüsselung einrichten…',
      onClose: () => _close(success: false),
      child: const Center(
        child: Padding(
          padding: EdgeInsets.all(32),
          child: CircularProgressIndicator.adaptive(),
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Sub-widgets
// ─────────────────────────────────────────────────────────────────────────────

class _Shell extends StatelessWidget {
  final PyramidTheme pt;
  final String title;
  final VoidCallback? onClose;
  final Widget child;

  const _Shell({
    required this.pt,
    required this.title,
    required this.onClose,
    required this.child,
  });

  @override
  Widget build(BuildContext context) {
    return Dialog(
      backgroundColor: pt.bg1,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(pt.rBase + 4),
      ),
      child: ConstrainedBox(
        constraints: const BoxConstraints(
          maxWidth: 460,
          minWidth: 320,
          minHeight: 120,
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Header
            Padding(
              padding: const EdgeInsets.fromLTRB(20, 16, 12, 12),
              child: Row(
                children: [
                  Icon(Icons.shield_outlined, size: 18, color: pt.accent),
                  const SizedBox(width: 8),
                  Expanded(
                    child: Text(
                      title,
                      style: TextStyle(
                        color: pt.fg,
                        fontSize: 15,
                        fontWeight: FontWeight.w600,
                      ),
                    ),
                  ),
                  if (onClose != null)
                    IconButton(
                      icon: Icon(Icons.close_rounded, color: pt.fgDim, size: 16),
                      onPressed: onClose,
                      tooltip: 'Überspringen',
                      padding: EdgeInsets.zero,
                      constraints: const BoxConstraints(maxWidth: 28, maxHeight: 28),
                    ),
                ],
              ),
            ),
            Divider(color: pt.border, height: 1),
            child,
          ],
        ),
      ),
    );
  }
}

class _KeyInputBody extends StatelessWidget {
  final PyramidTheme pt;
  final TextEditingController ctrl;
  final bool loading;
  final String? error;
  final VoidCallback onUnlock;
  final VoidCallback onWipe;

  const _KeyInputBody({
    required this.pt,
    required this.ctrl,
    required this.loading,
    required this.error,
    required this.onUnlock,
    required this.onWipe,
  });

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 16, 20, 20),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'Gib deinen Wiederherstellungsschlüssel ein, um deine verschlüsselten Nachrichten lesbar zu machen.',
            style: TextStyle(color: pt.fgMuted, fontSize: 13, height: 1.5),
          ),
          const SizedBox(height: 16),
          TextField(
            controller: ctrl,
            readOnly: loading,
            autofocus: true,
            autocorrect: false,
            style: TextStyle(
              color: pt.fg,
              fontSize: 13,
              fontFamily: 'monospace',
            ),
            decoration: InputDecoration(
              hintText: 'EsXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX',
              hintStyle: TextStyle(color: pt.fgDim, fontSize: 12),
              labelText: 'Wiederherstellungsschlüssel',
              labelStyle: TextStyle(color: pt.fgMuted, fontSize: 13),
              errorText: error,
              errorMaxLines: 2,
              filled: true,
              fillColor: pt.bg2,
              prefixIcon: Icon(Icons.vpn_key_outlined, color: pt.fgDim, size: 18),
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(8),
                borderSide: BorderSide(color: pt.border),
              ),
              enabledBorder: OutlineInputBorder(
                borderRadius: BorderRadius.circular(8),
                borderSide: BorderSide(color: pt.border),
              ),
              focusedBorder: OutlineInputBorder(
                borderRadius: BorderRadius.circular(8),
                borderSide: BorderSide(color: pt.accent),
              ),
              isDense: true,
              contentPadding: const EdgeInsets.symmetric(
                horizontal: 12,
                vertical: 12,
              ),
            ),
            cursorColor: pt.accent,
            onSubmitted: (_) => onUnlock(),
          ),
          const SizedBox(height: 16),
          SizedBox(
            width: double.infinity,
            child: ElevatedButton.icon(
              style: ElevatedButton.styleFrom(
                backgroundColor: pt.accent,
                foregroundColor: pt.accentFg,
                padding: const EdgeInsets.symmetric(vertical: 12),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
                elevation: 0,
              ),
              onPressed: loading ? null : onUnlock,
              icon: loading
                  ? SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(
                        color: pt.accentFg,
                        strokeWidth: 2,
                      ),
                    )
                  : const Icon(Icons.lock_open_outlined, size: 18),
              label: Text(
                loading ? 'Entschlüssele…' : 'Nachrichten entschlüsseln',
              ),
            ),
          ),
          const SizedBox(height: 12),
          // Divider + lost key option
          Row(
            children: [
              Expanded(child: Divider(color: pt.border)),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 12),
                child: Text('oder', style: TextStyle(color: pt.fgDim, fontSize: 12)),
              ),
              Expanded(child: Divider(color: pt.border)),
            ],
          ),
          const SizedBox(height: 12),
          SizedBox(
            width: double.infinity,
            child: OutlinedButton.icon(
              style: OutlinedButton.styleFrom(
                foregroundColor: PyramidColors.danger,
                side: BorderSide(color: PyramidColors.danger.withAlpha(100)),
                padding: const EdgeInsets.symmetric(vertical: 10),
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(8),
                ),
              ),
              onPressed: loading ? null : onWipe,
              icon: const Icon(Icons.delete_outlined, size: 16),
              label: const Text('Schlüssel verloren — neu einrichten', style: TextStyle(fontSize: 13)),
            ),
          ),
        ],
      ),
    );
  }
}

class _DoneBody extends StatelessWidget {
  final PyramidTheme pt;
  final VoidCallback onClose;

  const _DoneBody({required this.pt, required this.onClose});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(
            Icons.check_circle_outline_rounded,
            color: PyramidColors.success,
            size: 56,
          ),
          const SizedBox(height: 12),
          Text(
            'Alle Schlüssel wurden erfolgreich importiert.',
            textAlign: TextAlign.center,
            style: TextStyle(color: pt.fg, fontSize: 14, fontWeight: FontWeight.w500),
          ),
          const SizedBox(height: 6),
          Text(
            'Deine verschlüsselten Nachrichten werden jetzt im Hintergrund entschlüsselt.',
            textAlign: TextAlign.center,
            style: TextStyle(color: pt.fgMuted, fontSize: 13, height: 1.5),
          ),
          const SizedBox(height: 20),
          SizedBox(
            width: double.infinity,
            child: ElevatedButton(
              style: ElevatedButton.styleFrom(
                backgroundColor: pt.accent,
                foregroundColor: pt.accentFg,
                padding: const EdgeInsets.symmetric(vertical: 12),
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
                elevation: 0,
              ),
              onPressed: onClose,
              child: const Text('Fertig'),
            ),
          ),
        ],
      ),
    );
  }
}

class _ErrorBody extends StatelessWidget {
  final PyramidTheme pt;
  final VoidCallback onClose;

  const _ErrorBody({required this.pt, required this.onClose});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 20, 20, 20),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.error_outline_rounded, color: PyramidColors.danger, size: 48),
          const SizedBox(height: 12),
          Text(
            'Etwas ist schiefgelaufen. Versuche es erneut.',
            textAlign: TextAlign.center,
            style: TextStyle(color: pt.fgMuted, fontSize: 13),
          ),
          const SizedBox(height: 20),
          SizedBox(
            width: double.infinity,
            child: OutlinedButton(
              style: OutlinedButton.styleFrom(
                foregroundColor: pt.fg,
                side: BorderSide(color: pt.border),
                padding: const EdgeInsets.symmetric(vertical: 12),
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
              ),
              onPressed: onClose,
              child: const Text('Schließen'),
            ),
          ),
        ],
      ),
    );
  }
}
