import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:matrix/encryption/utils/key_verification.dart' show KeyVerification, KeyVerificationEmoji, KeyVerificationState;
import 'package:matrix/matrix.dart';
import 'package:pretty_qr_code/pretty_qr_code.dart';
import 'package:pyramid/core/app_state.dart';
import 'package:pyramid/core/matrix_client.dart';
import 'package:pyramid/core/theme.dart';
import 'package:pyramid/core/voip_manager.dart';
import 'package:pyramid/features/auth/bootstrap_dialog.dart';
import 'package:pyramid/features/call/voice_channel.dart';
import 'package:pyramid/features/chat/chat_view.dart';
import 'package:pyramid/features/members/members_panel.dart';
import 'package:pyramid/features/rooms/rooms_panel.dart';
import 'package:pyramid/features/spaces/spaces_rail.dart';
import 'package:pyramid/widgets/search_modal.dart';
import 'package:pyramid/widgets/settings_modal.dart';
import 'package:pyramid/widgets/share_target_dialog.dart';
import 'package:pyramid/core/notification_service.dart';
import 'package:pyramid/widgets/update_banner.dart';

class AppShell extends ConsumerStatefulWidget {
  const AppShell({super.key});

  @override
  ConsumerState<AppShell> createState() => _AppShellState();
}

class _AppShellState extends ConsumerState<AppShell>
    with WidgetsBindingObserver {
  double _sidebarWidth = 260;
  bool _bootstrapTriggered = false;
  // Flankenerkennung für die Auto-Switch-Listener (siehe build).
  bool _wasVoipConnected = false;
  bool _wasLiveKitActive = false;
  StreamSubscription<KeyVerification>? _verificationSub;
  Timer? _presenceTimer;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _triggerBootstrap();
      _subscribeVerification();
      initNotifications(ref);
      _startPresenceHeartbeat();
    });
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _verificationSub?.cancel();
    _presenceTimer?.cancel();
    super.dispose();
  }

  /// Sends `setPresence(online)` every 55 seconds while the app is active.
  /// This prevents the server from marking us offline due to inactivity timeout.
  void _startPresenceHeartbeat() async {
    _presenceTimer?.cancel();
    final client = await ref.read(matrixClientProvider.future);
    if (!mounted) return;
    _sendPresence(client, true);
    _presenceTimer = Timer.periodic(const Duration(seconds: 55), (_) {
      _sendPresence(client, true);
    });
  }

  void _sendPresence(Client client, bool online) {
    client
        .setPresence(
          client.userID!,
          online ? PresenceType.online : PresenceType.unavailable,
        )
        .catchError((_) {});
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    // Update focus state immediately — used by notification suppression logic.
    ref.read(windowFocusedProvider.notifier).state =
        state == AppLifecycleState.resumed;
    ref.read(matrixClientProvider.future).then((client) {
      if (!mounted) return;
      if (state == AppLifecycleState.resumed) {
        _sendPresence(client, true);
        // Restart heartbeat timer after coming back from background.
        _presenceTimer?.cancel();
        _presenceTimer = Timer.periodic(const Duration(seconds: 55), (_) {
          _sendPresence(client, true);
        });
        // Advance the notification watch time so catch-up events from the initial
        // sync (already shown by the FCM background handler) are not shown again.
        resetNotificationStartTime();
        // Send any inline reply stored by the background notification handler.
        checkPendingReply(ref);
      } else if (state == AppLifecycleState.paused ||
          state == AppLifecycleState.detached) {
        _presenceTimer?.cancel();
        _sendPresence(client, false);
      }
    }).catchError((_) {});
  }

  void _triggerBootstrap() async {
    if (_bootstrapTriggered) return;
    final client = await ref.read(matrixClientProvider.future);
    if (client.encryption?.crossSigning.enabled != true) {
      if (mounted) {
        setState(() => _bootstrapTriggered = true);
        showBootstrapDialog(context, client);
      }
    }
  }

  void _subscribeVerification() async {
    final client = await ref.read(matrixClientProvider.future);
    if (!mounted) return;
    _verificationSub = client.onKeyVerificationRequest.stream.listen((request) {
      if (!mounted) return;
      // Only show dialog if it's in askAccept state (incoming request not yet handled)
      if (request.state == KeyVerificationState.askAccept) {
        showDialog<void>(
          context: context,
          barrierDismissible: false,
          builder: (ctx) => _IncomingVerificationDialog(
            request: request,
            pt: PyramidTheme.of(context),
          ),
        );
      }
    });
  }

  void onSidebarResize(double delta) {
    setState(() {
      _sidebarWidth = (_sidebarWidth + delta).clamp(200.0, 500.0);
    });
  }

  void onCloseModal() {
    ref.read(activeModalProvider.notifier).state = ModalKind.none;
  }

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

    // Activate notification watcher (no-op after first call)
    ref.watch(notificationWatcherProvider);

    // Auto-switch to voice view when call is connected — but only on the
    // transition into the connected state. The provider feuert bei jedem
    // notifyListeners (u.a. Render-Timer im Sekundentakt); ohne Flankenerkennung
    // würde der Nutzer permanent zurück in die Call-UI gezwungen und könnte
    // sie nie minimieren.
    ref.listen(voipStateProvider, (prev, next) {
      final wasConnected = _wasVoipConnected;
      final isConnected = next.currentCall != null &&
          next.currentCall!.state == CallState.kConnected;
      _wasVoipConnected = isConnected;
      if (isConnected && !wasConnected) {
        if (ref.read(viewModeProvider) != ViewMode.voice) {
          ref.read(viewModeProvider.notifier).state = ViewMode.voice;
        }
      }
    });

    ref.listen(callStateProvider, (prev, next) {
      // Only auto-switch to voice view for video/audio calls, NOT voice channels
      // (voice channels should stay in background with a mini bar)
      final wasActive = _wasLiveKitActive;
      final isActiveCall = next.isActive && !next.isConnecting && !next.isVoiceChannel;
      _wasLiveKitActive = isActiveCall;
      if (isActiveCall && !wasActive) {
        if (ref.read(viewModeProvider) != ViewMode.voice) {
          ref.read(viewModeProvider.notifier).state = ViewMode.voice;
        }
      }
    });

    // "Teilen nach Pyramid" (Android): geteilte Inhalte → Raum-Picker zeigen.
    ref.listen(pendingShareProvider, (prev, next) {
      if (next != null && !next.isEmpty) {
        ref.read(pendingShareProvider.notifier).state = null;
        ShareTargetDialog.show(context, ref, next);
      }
    });

    final sidebarWidth = _sidebarWidth;
    final railCollapsed = ref.watch(railCollapsedProvider);
    final activeRoomId = ref.watch(activeRoomIdProvider);
    final viewMode = ref.watch(viewModeProvider);
    final activeModal = ref.watch(activeModalProvider);
    final membersOpen = ref.watch(membersPanelOpenProvider);
    final innerPt = PyramidTheme.of(context);
    final voip = ref.watch(voipStateProvider);

    final size = MediaQuery.sizeOf(context);
    final isMobile = size.width < 900 || size.height < 500;
    
    // Auto-close members panel if screen gets too small
    if (!isMobile && size.width < 1100 && membersOpen) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        ref.read(membersPanelOpenProvider.notifier).state = false;
      });
    }

    if (isMobile) {
      return _MobileShell(
        pt: innerPt,
        activeRoomId: activeRoomId,
        viewMode: viewMode,
        activeModal: activeModal,
        membersOpen: membersOpen,
        onCloseModal: onCloseModal,
      );
    }

    return Scaffold(
      backgroundColor: pt.bg1,
      body: PopScope(
        canPop: false,
        onPopInvokedWithResult: (didPop, _) {
          if (activeModal != ModalKind.none) {
            onCloseModal();
          }
        },
        child: Column(
          children: [
            const UpdateBanner(),
            const _NotificationBlockedBanner(),
            Expanded(child: Stack(
          children: [
            Row(
              children: [
                // Spaces rail
                AnimatedContainer(
                  duration: const Duration(milliseconds: 250),
                  curve: Curves.easeOutCubic,
                  width: railCollapsed ? 0 : 72,
                  clipBehavior: Clip.hardEdge,
                  decoration: const BoxDecoration(),
                  child: const SpacesRail(),
                ),
                // Rooms panel with resizable divider
                SizedBox(
                  width: sidebarWidth.clamp(200.0, size.width * 0.4),
                  child: const RoomsPanel(),
                ),
                _ResizeDivider(
                  pt: innerPt,
                  onDrag: onSidebarResize,
                ),
                // Main content
                Expanded(
                  child: viewMode == ViewMode.voice
                      ? const VoiceChannelView()
                      : activeRoomId != null
                          ? ChatView(roomId: activeRoomId)
                          : const NoChatSelected(),
                ),
                // Members panel — only if enough space (min 1100px total width)
                if (membersOpen && activeRoomId != null && viewMode != ViewMode.voice && size.width >= 1100)
                  MembersPanel(roomId: activeRoomId),
              ],
            ),
            // Incoming Call Popup for Desktop
            if (voip.currentCall != null && voip.currentCall!.state == CallState.kRinging)
              _IncomingCallOverlay(call: voip.currentCall!, voip: voip, pt: pt),

            // Modal overlays
            if (activeModal == ModalKind.settings)
              SettingsModal(onClose: onCloseModal),
            if (activeModal == ModalKind.search)
              SearchModal(onClose: onCloseModal),

            // Members panel as overlay if screen is narrow but requested
            if (membersOpen && activeRoomId != null && viewMode != ViewMode.voice && size.width < 1100) ...[
              Positioned.fill(
                child: GestureDetector(
                  onTap: () => ref.read(membersPanelOpenProvider.notifier).state = false,
                  child: Container(color: Colors.black.withAlpha(110)),
                ),
              ),
              Positioned(
                right: 0,
                top: 0,
                bottom: 0,
                child: Container(
                  decoration: BoxDecoration(
                    boxShadow: [BoxShadow(color: Colors.black45, blurRadius: 16)],
                  ),
                  child: MembersPanel(
                    roomId: activeRoomId,
                    onClose: () => ref.read(membersPanelOpenProvider.notifier).state = false,
                  ),
                ),
              ),
            ],
          ],
        )),   // end Stack + Expanded
          ],
        ),    // end Column
      ),
    );
  }
}

class _MobileShell extends ConsumerWidget {
  final PyramidTheme pt;
  final String? activeRoomId;
  final ViewMode viewMode;
  final ModalKind activeModal;
  final bool membersOpen;
  final VoidCallback onCloseModal;

  const _MobileShell({
    required this.pt,
    required this.activeRoomId,
    required this.viewMode,
    required this.activeModal,
    required this.membersOpen,
    required this.onCloseModal,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final voip = ref.watch(voipStateProvider);

    Widget body;
    if (viewMode == ViewMode.voice) {
      body = const VoiceChannelView();
    } else if (activeRoomId != null) {
      body = ChatView(roomId: activeRoomId!);
    } else {
      body = const RoomsPanel();
    }

    return PopScope(
      canPop: activeRoomId == null && viewMode == ViewMode.chat && !membersOpen,
      onPopInvokedWithResult: (didPop, _) {
        if (!didPop) {
          if (membersOpen) {
            ref.read(membersPanelOpenProvider.notifier).state = false;
          } else if (viewMode == ViewMode.voice) {
            ref.read(viewModeProvider.notifier).state = ViewMode.chat;
          } else if (activeRoomId != null) {
            ref.read(activeRoomIdProvider.notifier).state = null;
          }
        }
      },
      child: Scaffold(
        backgroundColor: pt.bg0,
        drawer: Drawer(
          width: 80,
          backgroundColor: pt.bg0,
          child: const SpacesRail(),
        ),
        body: Stack(
          children: [
            body,
            if (membersOpen && activeRoomId != null && viewMode != ViewMode.voice) ...[
              // Tap-outside scrim closes the panel
              Positioned.fill(
                child: GestureDetector(
                  onTap: () => ref.read(membersPanelOpenProvider.notifier).state = false,
                  child: Container(color: Colors.black.withAlpha(110)),
                ),
              ),
              Positioned(
                right: 0,
                top: 0,
                bottom: 0,
                child: Builder(builder: (ctx) {
                  final w = MediaQuery.sizeOf(ctx).width;
                  return MembersPanel(
                    roomId: activeRoomId!,
                    width: (w * 0.82).clamp(240.0, 320.0),
                    onClose: () => ref.read(membersPanelOpenProvider.notifier).state = false,
                  );
                }),
              ),
            ],
            if (voip.currentCall != null && voip.currentCall!.state == CallState.kRinging)
              _IncomingCallOverlay(call: voip.currentCall!, voip: voip, pt: pt),
            if (activeModal == ModalKind.settings)
              SettingsModal(onClose: onCloseModal),
            if (activeModal == ModalKind.search)
              SearchModal(onClose: onCloseModal),
            const Positioned(
              top: 0, left: 0, right: 0,
              child: _NotificationBlockedBanner(),
            ),
          ],
        ),
      ),
    );
  }
}

class _NotificationBlockedBanner extends ConsumerWidget {
  const _NotificationBlockedBanner();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final blocked = ref.watch(notificationsBlockedProvider);
    if (!blocked) return const SizedBox.shrink();

    return Material(
      color: Colors.transparent,
      child: Container(
        color: const Color(0xFFF5A623),
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
        child: Row(
          children: [
            const Icon(Icons.notifications_off, size: 16, color: Colors.white),
            const SizedBox(width: 8),
            Expanded(
              child: Text(
                'Benachrichtigungen sind deaktiviert',
                style: TextStyle(color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500),
              ),
            ),
            TextButton(
              onPressed: () {
                openNotificationSettings();
                ref.read(notificationsBlockedProvider.notifier).state = false;
              },
              style: TextButton.styleFrom(
                foregroundColor: Colors.white,
                padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                minimumSize: Size.zero,
                tapTargetSize: MaterialTapTargetSize.shrinkWrap,
              ),
              child: const Text('Einstellungen', style: TextStyle(fontSize: 12, decoration: TextDecoration.underline)),
            ),
            IconButton(
              icon: const Icon(Icons.close, size: 14, color: Colors.white),
              padding: const EdgeInsets.all(4),
              constraints: const BoxConstraints(),
              onPressed: () => ref.read(notificationsBlockedProvider.notifier).state = false,
            ),
          ],
        ),
      ),
    );
  }
}

class _IncomingCallOverlay extends ConsumerWidget {
  final CallSession call;
  final PyramidVoipManager voip;
  final PyramidTheme pt;

  const _IncomingCallOverlay({
    required this.call,
    required this.voip,
    required this.pt,
  });

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container(
      color: Colors.black.withAlpha(180),
      child: Center(
        child: Container(
          width: 320,
          padding: const EdgeInsets.all(32),
          decoration: BoxDecoration(
            color: pt.bg2,
            borderRadius: BorderRadius.circular(pt.rXl),
            border: Border.all(color: pt.border),
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Container(
                width: 80,
                height: 80,
                decoration: BoxDecoration(
                  color: pt.accent,
                  shape: BoxShape.circle,
                ),
                child: const Icon(Icons.person_rounded, size: 40, color: Colors.white),
              ),
              const SizedBox(height: 24),
              Text(
                'Eingehender Anruf',
                style: TextStyle(color: pt.fgDim, fontSize: 13),
              ),
              const SizedBox(height: 8),
              Text(
                call.room.getLocalizedDisplayname(),
                style: TextStyle(color: pt.fg, fontSize: 18, fontWeight: FontWeight.w700),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 32),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  FloatingActionButton(
                    heroTag: 'reject_call',
                    onPressed: () => voip.safeAction(() async => await call.reject()),
                    backgroundColor: pt.danger,
                    child: const Icon(Icons.call_end_rounded, color: Colors.white),
                  ),
                  FloatingActionButton(
                    heroTag: 'answer_call',
                    onPressed: () {
                      ref.read(viewModeProvider.notifier).state = ViewMode.voice;
                      voip.safeAction(() async => await call.answer());
                    },
                    backgroundColor: pt.online,
                    child: const Icon(Icons.call_rounded, color: Colors.white),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _ResizeDivider extends StatefulWidget {
  final PyramidTheme pt;
  final ValueChanged<double> onDrag;

  const _ResizeDivider({required this.pt, required this.onDrag});

  @override
  State<_ResizeDivider> createState() => _ResizeDividerState();
}

class _ResizeDividerState extends State<_ResizeDivider> {
  bool _hovered = false;

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      cursor: SystemMouseCursors.resizeColumn,
      onEnter: (_) => setState(() => _hovered = true),
      onExit: (_) => setState(() => _hovered = false),
      child: GestureDetector(
        behavior: HitTestBehavior.translucent,
        onHorizontalDragUpdate: (d) => widget.onDrag(d.delta.dx),
        child: AnimatedContainer(
          duration: const Duration(milliseconds: 150),
          width: 6,
          color: _hovered ? widget.pt.accent.withAlpha(80) : widget.pt.border,
        ),
      ),
    );
  }
}

class NoChatSelected extends StatelessWidget {
  const NoChatSelected({super.key});

  @override
  Widget build(BuildContext context) {
    final pt = PyramidTheme.of(context);
    return Center(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.chat_bubble_outline_rounded, size: 64, color: pt.fgDim.withAlpha(50)),
          const SizedBox(height: 16),
          Text(
            'Select a chat to start messaging',
            style: TextStyle(color: pt.fgMuted, fontSize: 15),
          ),
        ],
      ),
    );
  }
}

// ─── Incoming Key Verification Dialog ───────────────────────────────────────

class _IncomingVerificationDialog extends StatefulWidget {
  final KeyVerification request;
  final PyramidTheme pt;

  const _IncomingVerificationDialog({
    required this.request,
    required this.pt,
  });

  @override
  State<_IncomingVerificationDialog> createState() =>
      _IncomingVerificationDialogState();
}

class _IncomingVerificationDialogState
    extends State<_IncomingVerificationDialog> {
  late KeyVerificationState _state;

  @override
  void initState() {
    super.initState();
    _state = widget.request.state;
    widget.request.onUpdate = () {
      if (mounted) setState(() => _state = widget.request.state);
    };
  }

  @override
  void dispose() {
    if (!widget.request.isDone) {
      widget.request.cancel('m.user').catchError((_) {});
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final pt = widget.pt;
    final req = widget.request;

    return AlertDialog(
      backgroundColor: pt.bg2,
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(16),
          side: BorderSide(color: pt.border)),
      contentPadding: const EdgeInsets.fromLTRB(24, 20, 24, 0),
      title: Row(
        children: [
          Icon(Icons.verified_user_outlined, size: 20, color: pt.accent),
          const SizedBox(width: 10),
          Expanded(
            child: Text(
              'Verifikationsanfrage',
              style: TextStyle(color: pt.fg, fontSize: 16, fontWeight: FontWeight.w700),
            ),
          ),
        ],
      ),
      content: SizedBox(
        width: 380,
        child: _buildContent(pt, req),
      ),
      actions: _buildActions(pt, req),
    );
  }

  Widget _buildContent(PyramidTheme pt, KeyVerification req) {
    return switch (_state) {
      KeyVerificationState.askAccept => Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _VerifInfoRow(
              icon: Icons.devices_rounded,
              label: (req.deviceId?.isNotEmpty == true) ? req.deviceId! : 'Unbekanntes Gerät',
              pt: pt,
            ),
            const SizedBox(height: 6),
            _VerifInfoRow(
              icon: Icons.person_outline_rounded,
              label: req.userId,
              pt: pt,
            ),
            const SizedBox(height: 12),
            Text(
              'Dieses Gerät möchte sich mit deinem Konto verifizieren.',
              style: TextStyle(color: pt.fgMuted, fontSize: 13, height: 1.5),
            ),
          ],
        ),
      ),
      KeyVerificationState.waitingAccept => Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: Column(mainAxisSize: MainAxisSize.min, children: [
          const CircularProgressIndicator.adaptive(),
          const SizedBox(height: 16),
          Text('Bereite Verifikation vor…',
              style: TextStyle(color: pt.fgMuted, fontSize: 13)),
        ]),
      ),
      KeyVerificationState.askChoice => Padding(
        padding: const EdgeInsets.only(bottom: 8),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Text(
              'Wähle eine Verifikationsmethode:',
              style: TextStyle(color: pt.fgMuted, fontSize: 13),
            ),
            const SizedBox(height: 16),
            ElevatedButton.icon(
              style: ElevatedButton.styleFrom(
                backgroundColor: pt.accent,
                foregroundColor: pt.accentFg,
                elevation: 0,
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
                padding: const EdgeInsets.symmetric(vertical: 12),
              ),
              onPressed: () => req.continueVerification('m.sas.v1').catchError((_) {}),
              icon: const Icon(Icons.tag_faces_rounded, size: 18),
              label: const Text('Emoji-Verifikation'),
            ),
            const SizedBox(height: 8),
            ElevatedButton.icon(
              style: ElevatedButton.styleFrom(
                backgroundColor: pt.bg3,
                foregroundColor: pt.fg,
                elevation: 0,
                shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
                padding: const EdgeInsets.symmetric(vertical: 12),
              ),
              onPressed: () => req.continueVerification('m.qr_code.show.v1').catchError((_) {}),
              icon: const Icon(Icons.qr_code_rounded, size: 18),
              label: const Text('QR-Code anzeigen'),
            ),
            const SizedBox(height: 8),
          ],
        ),
      ),
      KeyVerificationState.confirmQRScan => _QrCodeDisplay(pt: pt, request: req),
      KeyVerificationState.showQRSuccess => Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: _InfoCard(
            pt: pt,
            icon: Icons.verified_rounded,
            color: const Color(0xFF22C55E),
            text: 'QR-Code erfolgreich gescannt. Verifikation abgeschlossen.'),
      ),
      KeyVerificationState.askSas => _SasView(request: req, pt: pt, onClose: () => Navigator.pop(context)),
      KeyVerificationState.waitingSas => Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: Column(mainAxisSize: MainAxisSize.min, children: [
          const CircularProgressIndicator.adaptive(),
          const SizedBox(height: 16),
          Text('Warte auf Bestätigung der anderen Seite…',
              style: TextStyle(color: pt.fgMuted, fontSize: 13)),
        ]),
      ),
      KeyVerificationState.done => Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: _InfoCard(
            pt: pt,
            icon: Icons.verified_rounded,
            color: const Color(0xFF22C55E),
            text: 'Gerät erfolgreich verifiziert.'),
      ),
      _ => Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: _InfoCard(
            pt: pt,
            icon: Icons.error_outline_rounded,
            color: pt.danger,
            text: 'Verifizierung fehlgeschlagen oder abgebrochen.'),
      ),
    };
  }

  List<Widget> _buildActions(PyramidTheme pt, KeyVerification req) {
    if (_state == KeyVerificationState.askAccept) {
      return [
        TextButton(
          onPressed: () {
            req.cancel('m.user').catchError((_) {});
            Navigator.pop(context);
          },
          child: Text('Ablehnen', style: TextStyle(color: pt.danger)),
        ),
        ElevatedButton(
          style: ElevatedButton.styleFrom(
              backgroundColor: pt.accent,
              foregroundColor: pt.accentFg,
              elevation: 0,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
          onPressed: () => req.acceptVerification().catchError((_) {}),
          child: const Text('Annehmen'),
        ),
      ];
    }
    if (_state == KeyVerificationState.confirmQRScan) {
      return [
        TextButton(
          onPressed: () {
            req.cancel('m.user').catchError((_) {});
            Navigator.pop(context);
          },
          child: Text('Abbrechen', style: TextStyle(color: pt.fgMuted)),
        ),
        ElevatedButton(
          style: ElevatedButton.styleFrom(
              backgroundColor: const Color(0xFF22C55E),
              foregroundColor: Colors.white,
              elevation: 0,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
          onPressed: () => req.acceptQRScanConfirmation().catchError((_) {}),
          child: const Text('Gescannt bestätigen'),
        ),
      ];
    }
    if (_state == KeyVerificationState.done ||
        _state == KeyVerificationState.showQRSuccess ||
        _state == KeyVerificationState.error) {
      return [
        ElevatedButton(
          style: ElevatedButton.styleFrom(
              backgroundColor: pt.accent,
              foregroundColor: pt.accentFg,
              elevation: 0,
              shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8))),
          onPressed: () => Navigator.pop(context),
          child: const Text('Schließen'),
        ),
      ];
    }
    if (_state == KeyVerificationState.askSas || _state == KeyVerificationState.askChoice) return [];
    return [
      TextButton(
        onPressed: () {
          req.cancel('m.user').catchError((_) {});
          Navigator.pop(context);
        },
        child: Text('Abbrechen', style: TextStyle(color: pt.fgMuted)),
      ),
    ];
  }
}

class _SasView extends StatelessWidget {
  final KeyVerification request;
  final PyramidTheme pt;
  final VoidCallback onClose;

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

  @override
  Widget build(BuildContext context) {
    final emojis = request.sasEmojis;
    return Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(
            'Vergleiche die Emojis auf beiden Geräten',
            textAlign: TextAlign.center,
            style: TextStyle(color: pt.fgMuted, fontSize: 13),
          ),
          const SizedBox(height: 20),
          if (emojis.isNotEmpty)
            Wrap(
              spacing: 10,
              runSpacing: 10,
              alignment: WrapAlignment.center,
              children: emojis.map((e) => _EmojiChip(emoji: e, pt: pt)).toList(),
            )
          else
            Text('Keine Emojis verfügbar', style: TextStyle(color: pt.fgDim, fontSize: 13)),
          const SizedBox(height: 24),
          Text(
            'Stimmen alle Emojis überein?',
            style: TextStyle(color: pt.fg, fontSize: 14, fontWeight: FontWeight.w600),
          ),
          const SizedBox(height: 16),
          Row(
            children: [
              Expanded(
                child: OutlinedButton.icon(
                  style: OutlinedButton.styleFrom(
                    foregroundColor: pt.danger,
                    side: BorderSide(color: pt.danger.withAlpha(120)),
                    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
                    padding: const EdgeInsets.symmetric(vertical: 12),
                  ),
                  onPressed: () {
                    request.rejectSas().catchError((_) {});
                    onClose();
                  },
                  icon: const Icon(Icons.close_rounded, size: 16),
                  label: const Text('Stimmt nicht'),
                ),
              ),
              const SizedBox(width: 12),
              Expanded(
                child: ElevatedButton.icon(
                  style: ElevatedButton.styleFrom(
                    backgroundColor: const Color(0xFF22C55E),
                    foregroundColor: Colors.white,
                    elevation: 0,
                    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
                    padding: const EdgeInsets.symmetric(vertical: 12),
                  ),
                  onPressed: () => request.acceptSas().catchError((_) {}),
                  icon: const Icon(Icons.check_rounded, size: 16),
                  label: const Text('Stimmt überein'),
                ),
              ),
            ],
          ),
          const SizedBox(height: 8),
        ],
      ),
    );
  }
}

class _EmojiChip extends StatelessWidget {
  final KeyVerificationEmoji emoji;
  final PyramidTheme pt;
  const _EmojiChip({required this.emoji, required this.pt});

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 64,
      padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
      decoration: BoxDecoration(
        color: pt.bg3,
        borderRadius: BorderRadius.circular(10),
        border: Border.all(color: pt.border),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(emoji.emoji, style: const TextStyle(fontSize: 24)),
          const SizedBox(height: 4),
          Text(
            emoji.name,
            style: TextStyle(color: pt.fgMuted, fontSize: 9),
            textAlign: TextAlign.center,
            maxLines: 2,
            overflow: TextOverflow.ellipsis,
          ),
        ],
      ),
    );
  }
}

class _VerifInfoRow extends StatelessWidget {
  final IconData icon;
  final String label;
  final PyramidTheme pt;
  const _VerifInfoRow({required this.icon, required this.label, required this.pt});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Icon(icon, size: 14, color: pt.fgDim),
        const SizedBox(width: 8),
        Expanded(
          child: Text(
            label,
            style: TextStyle(color: pt.fg, fontSize: 12, fontFamily: 'monospace'),
            overflow: TextOverflow.ellipsis,
          ),
        ),
      ],
    );
  }
}

class _InfoCard extends StatelessWidget {
  final PyramidTheme pt;
  final IconData icon;
  final Color color;
  final String text;
  const _InfoCard({required this.pt, required this.icon, required this.color, required this.text});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: pt.bg2,
        borderRadius: BorderRadius.circular(8),
        border: Border.all(color: pt.border),
      ),
      child: Row(
        children: [
          Icon(icon, color: color, size: 18),
          const SizedBox(width: 10),
          Expanded(child: Text(text, style: TextStyle(color: pt.fgMuted, fontSize: 13))),
        ],
      ),
    );
  }
}

class _QrCodeDisplay extends StatelessWidget {
  final PyramidTheme pt;
  final KeyVerification request;

  const _QrCodeDisplay({required this.pt, required this.request});

  @override
  Widget build(BuildContext context) {
    final qrCode = request.qrCode;
    if (qrCode == null) {
      return Padding(
        padding: const EdgeInsets.symmetric(vertical: 24),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const CircularProgressIndicator.adaptive(),
            const SizedBox(height: 12),
            Text('QR-Code wird generiert…', style: TextStyle(color: pt.fgMuted, fontSize: 13)),
          ],
        ),
      );
    }

    try {
      final rawBytes = Uint8List.fromList(qrCode.qrDataRawBytes.toList());
      final qr = QrCode.fromUint8List(data: rawBytes, errorCorrectLevel: QrErrorCorrectLevel.L);
      final qrImage = QrImage(qr);

      return Padding(
        padding: const EdgeInsets.only(bottom: 8),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              'Scanne diesen QR-Code mit dem anderen Gerät',
              textAlign: TextAlign.center,
              style: TextStyle(color: pt.fgMuted, fontSize: 13),
            ),
            const SizedBox(height: 16),
            Center(
              child: Container(
                width: 220,
                height: 220,
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Colors.white,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: PrettyQrView(qrImage: qrImage),
              ),
            ),
            const SizedBox(height: 12),
            Text(
              'Sobald das andere Gerät den Code gescannt hat, tippe auf „Gescannt bestätigen".',
              textAlign: TextAlign.center,
              style: TextStyle(color: pt.fgDim, fontSize: 12),
            ),
            const SizedBox(height: 8),
          ],
        ),
      );
    } catch (_) {
      return Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: _InfoCard(
          pt: pt,
          icon: Icons.error_outline_rounded,
          color: pt.danger,
          text: 'QR-Code konnte nicht generiert werden.',
        ),
      );
    }
  }
}
