import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:url_launcher/url_launcher.dart';
import '../domain/linked_rp_launch.dart';
import '../domain/session_time_resolver.dart';
import '../domain/providers/linked_rps_provider.dart';
import '../domain/providers/user_sessions_provider.dart';
import '../../../../core/notifiers/auth_notifier.dart';
import '../../../../core/services/auth_proxy_service.dart';
import '../../../../core/services/logout_service.dart';
import '../../../../core/services/auth_token_store.dart';
import '../../../../core/i18n/locale_utils.dart';
import '../../../../core/widgets/language_selector.dart';
import '../../../../core/widgets/theme_toggle_button.dart';
import '../../../../core/ui/layout_breakpoints.dart';
import '../../../../core/ui/toast_service.dart';
import '../../profile/domain/notifiers/profile_notifier.dart';
import '../domain/dashboard_providers.dart';
import '../domain/models.dart' hide LinkedRp;
import 'audit_device_utils.dart';
import 'package:userfront/i18n.dart';

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

  @override
  ConsumerState<DashboardScreen> createState() => _DashboardScreenState();
}

class _DashboardScreenState extends ConsumerState<DashboardScreen> {
  static const double _dashboardCardSpacing = 12;
  static const double _dashboardCardMaxWidth = 228;
  static const double _activityDialogMaxWidth = 360;
  static const double _historySessionMinWidth = 92;
  static const double _historyOtherColumnsBaselineWidth = 780;
  static const int _historySessionMinVisibleChars = 8;
  static const double _historyDateColumnWidth = 132;
  static const double _historyAppColumnWidth = 132;
  static const double _historyIpColumnWidth = 118;
  static const double _historyDeviceColumnWidth = 128;
  static const double _historyBrowserColumnWidth = 112;
  static const double _historyAuthMethodColumnWidth = 108;
  static const double _historyResultColumnWidth = 88;
  static const double _historyStatusColumnWidth = 92;
  static const double _historyActionColumnWidth = 108;

  final ScrollController _pageScrollController = ScrollController();
  final ScrollController _rpScrollController = ScrollController();
  bool _isRevoking = false;
  String? _revokingSessionId;
  bool _redirectingToSignin = false;
  bool _authBootstrapInProgress = false;

  bool _showAllActivities = false;
  bool _showActiveSessionsOnly = false;
  bool _isDesktopSideMenuOpen = true;
  final Set<String> _revokedClientIds = {};

  Color get _ink => Theme.of(context).colorScheme.onSurface;
  Color get _surface => Theme.of(context).colorScheme.surface;
  Color get _border => Theme.of(context).colorScheme.outlineVariant;
  Color get _subtle => Theme.of(context).colorScheme.surfaceContainerLowest;

  String _renderTranslatedText(
    String key, {
    String? fallback,
    Map<String, String> values = const {},
  }) {
    var text = tr(key, fallback: fallback);
    values.forEach((name, value) {
      text = text.replaceAll('{{$name}}', value).replaceAll('{$name}', value);
    });
    return text;
  }

  @override
  void initState() {
    super.initState();
    _pageScrollController.addListener(_onPageScroll);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) {
        return;
      }
      unawaited(_bootstrapAuthAndLoad());
    });
  }

  @override
  void dispose() {
    _pageScrollController.dispose();
    _rpScrollController.dispose();
    super.dispose();
  }

  Future<void> _logout() async {
    await LogoutService().logout();
  }

  Future<void> _onRevokeLink(String clientId, String appName) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(tr('ui.userfront.dashboard.revoke.title')),
        content: Text(
          tr(
            'msg.userfront.dashboard.revoke.confirm',
            params: {'app': appName},
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: Text(tr('ui.common.cancel')),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            style: TextButton.styleFrom(foregroundColor: Colors.red),
            child: Text(tr('ui.userfront.dashboard.revoke.confirm_button')),
          ),
        ],
      ),
    );

    if (confirmed != true) return;

    setState(() => _isRevoking = true);
    try {
      await ref.read(linkedRpsProvider.notifier).revokeRp(clientId);
      if (mounted) {
        ToastService.success(
          tr(
            'msg.userfront.dashboard.revoke.success',
            params: {'app': appName},
          ),
        );
        setState(() {
          _revokedClientIds.add(clientId);
        });
        ref.invalidate(linkedRpsProvider);
      }
    } catch (e) {
      if (mounted) {
        ToastService.error(
          tr('msg.userfront.dashboard.revoke.error', params: {'error': '$e'}),
        );
      }
    } finally {
      if (mounted) {
        setState(() => _isRevoking = false);
      }
    }
  }

  Future<void> _onRevokeSession(UserSessionSummary session) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(tr('ui.userfront.dashboard.sessions.revoke.title')),
        content: Text(
          _renderTranslatedText(
            'msg.userfront.dashboard.sessions.revoke.confirm',
            values: {
              'target': session.isCurrent
                  ? tr('ui.userfront.dashboard.sessions.current_badge')
                  : _sessionDisplayLabel(session),
            },
          ),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: Text(tr('ui.common.cancel')),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            style: TextButton.styleFrom(foregroundColor: Colors.red),
            child: Text(tr('ui.userfront.dashboard.sessions.revoke.action')),
          ),
        ],
      ),
    );

    if (confirmed != true) {
      return;
    }

    setState(() => _revokingSessionId = session.sessionId);
    try {
      await ref
          .read(userSessionsProvider.notifier)
          .revokeSession(session.sessionId);
      if (!mounted) {
        return;
      }
      ToastService.success(
        tr('msg.userfront.dashboard.sessions.revoke.success'),
      );
    } catch (e) {
      if (!mounted) {
        return;
      }
      ToastService.error(
        tr(
          'msg.userfront.dashboard.sessions.revoke.error',
          params: {'error': '$e'},
        ),
      );
    } finally {
      if (mounted) {
        setState(() => _revokingSessionId = null);
      }
    }
  }

  void _onScanQR() {
    context.push('/scan');
  }

  void _onPageScroll() {
    if (!_pageScrollController.hasClients) {
      return;
    }
    if (_pageScrollController.position.extentAfter < 240) {
      ref.read(authTimelineProvider.notifier).loadMore();
    }
  }

  void _showRpDetails(_ActivityItem item) {
    showDialog(
      context: context,
      builder: (context) => Consumer(
        builder: (context, ref, _) {
          final dialogWidth = math.min(
            MediaQuery.sizeOf(context).width - 48,
            _activityDialogMaxWidth,
          );
          final statusLabel = item.status == 'active'
              ? tr('ui.userfront.dashboard.activity.linked')
              : tr('ui.userfront.dashboard.status.revoked');
          final statusColor = _activityStatusColor(item.status);

          return AlertDialog(
            backgroundColor: _surface,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(24),
            ),
            insetPadding: const EdgeInsets.symmetric(
              horizontal: 24,
              vertical: 24,
            ),
            contentPadding: const EdgeInsets.fromLTRB(20, 20, 20, 8),
            content: SizedBox(
              width: dialogWidth,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Container(
                    width: double.infinity,
                    padding: const EdgeInsets.all(16),
                    decoration: BoxDecoration(
                      color: _subtle,
                      borderRadius: BorderRadius.circular(18),
                      border: Border.all(color: _border),
                    ),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          item.appName,
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.w700,
                            color: _ink,
                          ),
                        ),
                        const SizedBox(height: 4),
                        Text(
                          tr('ui.common.details'),
                          style: TextStyle(
                            fontSize: 12,
                            fontWeight: FontWeight.w600,
                            color: Colors.grey[600],
                          ),
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(height: 16),
                  _buildActivityDetailSection(
                    title: tr('ui.userfront.dashboard.status_history'),
                    child: Row(
                      children: [
                        Expanded(
                          child: _buildActivityDetailField(
                            label: tr(
                              'ui.userfront.dashboard.link_status_label',
                            ),
                            value: statusLabel,
                            valueColor: statusColor,
                          ),
                        ),
                        const SizedBox(width: 10),
                        Expanded(
                          child: _buildActivityDetailField(
                            label: tr('ui.userfront.dashboard.last_auth_label'),
                            value: item.lastAuthAt,
                          ),
                        ),
                      ],
                    ),
                  ),
                  const SizedBox(height: 12),
                  _buildActivityDetailSection(
                    title: tr('ui.userfront.dashboard.scopes.title'),
                    child: item.scopes.isEmpty
                        ? Text(
                            tr('msg.userfront.dashboard.scopes.empty'),
                            style: TextStyle(
                              fontSize: 13,
                              color: Colors.grey[600],
                            ),
                          )
                        : Wrap(
                            spacing: 8,
                            runSpacing: 8,
                            children: item.scopes
                                .map(
                                  (scope) => Container(
                                    padding: const EdgeInsets.symmetric(
                                      horizontal: 10,
                                      vertical: 8,
                                    ),
                                    decoration: BoxDecoration(
                                      color: _subtle,
                                      borderRadius: BorderRadius.circular(12),
                                      border: Border.all(color: _border),
                                    ),
                                    child: Row(
                                      mainAxisSize: MainAxisSize.min,
                                      children: [
                                        Icon(
                                          Icons.shield_outlined,
                                          size: 14,
                                          color: _ink,
                                        ),
                                        const SizedBox(width: 6),
                                        Text(
                                          scope,
                                          style: TextStyle(
                                            fontSize: 12,
                                            fontWeight: FontWeight.w600,
                                            color: _ink,
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                )
                                .toList(),
                          ),
                  ),
                ],
              ),
            ),
            actionsPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
            actions: [
              SizedBox(
                width: double.infinity,
                child: TextButton(
                  onPressed: () => Navigator.of(context).pop(),
                  style: TextButton.styleFrom(
                    foregroundColor: _ink,
                    padding: const EdgeInsets.symmetric(vertical: 12),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                    backgroundColor: _subtle,
                  ),
                  child: Text(
                    tr('ui.common.close'),
                    style: const TextStyle(fontWeight: FontWeight.w600),
                  ),
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  Widget _buildActivityDetailSection({
    required String title,
    required Widget child,
  }) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(14),
      decoration: BoxDecoration(
        color: _surface,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: _border),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
            style: TextStyle(
              fontSize: 13,
              fontWeight: FontWeight.w700,
              color: _ink,
            ),
          ),
          const SizedBox(height: 10),
          child,
        ],
      ),
    );
  }

  Widget _buildActivityDetailField({
    required String label,
    required String value,
    Color? valueColor,
  }) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: _subtle,
        borderRadius: BorderRadius.circular(14),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            label,
            style: TextStyle(
              fontSize: 11,
              fontWeight: FontWeight.w600,
              color: Colors.grey[600],
            ),
          ),
          const SizedBox(height: 6),
          Text(
            value,
            style: TextStyle(
              fontSize: 14,
              fontWeight: FontWeight.w700,
              color: valueColor ?? _ink,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildSideMenu(BuildContext context, {required bool closeOnTap}) {
    return SafeArea(
      child: Column(
        children: [
          Expanded(
            child: ListView(
              padding: const EdgeInsets.symmetric(vertical: 12),
              children: [
                ListTile(
                  leading: const Icon(Icons.home_outlined),
                  title: Text(tr('ui.userfront.nav.dashboard')),
                  selected: true,
                  onTap: () {
                    if (closeOnTap) {
                      Navigator.of(context).pop();
                    }
                    context.go(buildLocalizedHomePath(Uri.base));
                  },
                ),
                ListTile(
                  leading: const Icon(Icons.person_outline),
                  title: Text(tr('ui.userfront.nav.profile')),
                  onTap: () {
                    if (closeOnTap) {
                      Navigator.of(context).pop();
                    }
                    context.push('/profile');
                  },
                ),
                ListTile(
                  leading: const Icon(Icons.qr_code_scanner),
                  title: Text(tr('ui.userfront.nav.qr_scan')),
                  onTap: () {
                    if (closeOnTap) {
                      Navigator.of(context).pop();
                    }
                    _onScanQR();
                  },
                ),
                const Divider(),
                ListTile(
                  leading: const Icon(Icons.logout),
                  title: Text(tr('ui.userfront.nav.logout')),
                  onTap: () async {
                    if (closeOnTap) {
                      Navigator.of(context).pop();
                    }
                    await _logout();
                  },
                ),
              ],
            ),
          ),
          const Padding(
            padding: EdgeInsets.only(bottom: 16),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                ThemeToggleButton(),
                SizedBox(height: 8),
                LanguageSelector(compact: true),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Future<void> _refreshAll() async {
    if (!_isLoggedIn()) {
      final recovered = await _recoverSessionFromCookie();
      if (!recovered) {
        _redirectToSignin();
        return;
      }
    }
    await ref.read(profileProvider.notifier).loadProfile();
    setState(() {
      _revokedClientIds.clear();
    });
    ref.invalidate(linkedRpsProvider);
    ref.invalidate(userSessionsProvider);

    await Future.wait([
      ref.read(linkedRpsProvider.future),
      ref.read(userSessionsProvider.future),
      ref.read(authTimelineProvider.notifier).refresh(),
    ]);

    await ref.read(linkedRpsProvider.notifier).refresh();
  }

  String _formatDateTime(DateTime dateTime) {
    final yyyy = dateTime.year.toString().padLeft(4, '0');
    final mm = dateTime.month.toString().padLeft(2, '0');
    final dd = dateTime.day.toString().padLeft(2, '0');
    final hh = dateTime.hour.toString().padLeft(2, '0');
    final min = dateTime.minute.toString().padLeft(2, '0');
    return '$yyyy.$mm.$dd $hh:$min';
  }

  Widget _selectableText(String text, {TextStyle? style}) {
    return SelectableText(text, style: style);
  }

  Widget _singleLineText(String text, {TextStyle? style}) {
    return Text(
      text,
      style: style,
      maxLines: 1,
      softWrap: false,
      overflow: TextOverflow.ellipsis,
      textAlign: TextAlign.center,
    );
  }

  String _authMethodLabel() {
    if (AuthTokenStore.usesCookie()) {
      return tr('ui.userfront.auth_method.ory');
    }
    final provider = AuthTokenStore.getProvider();
    if (provider == null || provider.isEmpty) {
      return tr('ui.userfront.auth_method.session');
    }
    final lower = provider.toLowerCase();
    if (lower.contains('ory')) {
      return tr('ui.userfront.auth_method.ory');
    }
    return provider;
  }

  String _deviceLabelFromUserAgent(String userAgent) {
    if (userAgent.isEmpty) {
      return tr('ui.common.hyphen', fallback: '-');
    }
    if (userAgent == headlessServerUserAgentSentinel) {
      return 'Headless(Server)';
    }
    final ua = userAgent.toLowerCase();
    if (ua.contains('iphone') || ua.contains('ipad') || ua.contains('ipod')) {
      return tr('ui.userfront.device.ios', fallback: 'Mobile(iOS)');
    }
    if (ua.contains('android')) {
      return tr('ui.userfront.device.android', fallback: 'Mobile(Android)');
    }
    if (ua.contains('windows')) {
      return tr('ui.userfront.device.windows', fallback: 'Desktop(Windows)');
    }
    if (ua.contains('mac os x') || ua.contains('macintosh')) {
      return tr('ui.userfront.device.macos', fallback: 'Desktop(macOS)');
    }
    if (ua.contains('linux')) {
      return tr('ui.userfront.device.linux', fallback: 'Desktop(Linux)');
    }
    return tr('ui.common.unknown', fallback: 'Unknown');
  }

  Widget _buildAuthMethodCell(AuditLogEntry log, String authMethod) {
    final isOidc = authMethod.contains('OIDC');
    if (authMethod != 'QR' && !isOidc) {
      final approvedUserAgent =
          log.detailMap['approved_user_agent']?.toString() ?? '';
      final approvedIp = log.detailMap['approved_ip']?.toString() ?? '';
      final hasApproverMeta =
          approvedUserAgent.isNotEmpty || approvedIp.isNotEmpty;
      if (!authMethod.startsWith('링크') || !hasApproverMeta) {
        return _selectableText(authMethod);
      }
      final deviceLabel = _deviceLabelFromUserAgent(approvedUserAgent);
      final tooltip = [
        tr(
          'msg.userfront.dashboard.approved_device',
          params: {'device': deviceLabel},
        ),
        tr(
          'msg.userfront.dashboard.approved_ip',
          params: {'ip': approvedIp.isEmpty ? '-' : approvedIp},
        ),
      ].join('\n');
      return Tooltip(
        message: tooltip,
        child: _selectableText(
          authMethod,
          style: const TextStyle(
            color: Colors.blueAccent,
            decoration: TextDecoration.underline,
          ),
        ),
      );
    }
    final approvedSessionId =
        (log.detailMap['approved_session_id']?.toString().trim().isNotEmpty ??
            false)
        ? log.detailMap['approved_session_id'].toString()
        : log.sessionId;
    final tooltipLabel = isOidc
        ? tr('ui.userfront.dashboard.approved_session.userfront')
        : tr('ui.userfront.dashboard.approved_session.default');
    final tooltip = approvedSessionId.isEmpty
        ? tr(
            'msg.userfront.dashboard.approved_session.none',
            params: {'label': tooltipLabel},
          )
        : tr(
            'msg.userfront.dashboard.approved_session.copy_click',
            params: {'label': tooltipLabel, 'id': approvedSessionId},
          );
    return InkWell(
      onTap: approvedSessionId.isEmpty
          ? null
          : () async {
              await Clipboard.setData(ClipboardData(text: approvedSessionId));
              if (mounted) {
                ToastService.info(
                  tr('msg.userfront.dashboard.session_id_copied'),
                );
              }
            },
      child: Tooltip(
        message: tooltip,
        child: Text(
          isOidc ? authMethod : tr('ui.common.qr', fallback: 'QR'),
          style: TextStyle(
            color: approvedSessionId.isEmpty ? _ink : Colors.blueAccent,
            decoration: approvedSessionId.isEmpty
                ? null
                : TextDecoration.underline,
          ),
        ),
      ),
    );
  }

  Widget _buildAuthMethodLine(AuditLogEntry log, String authMethod) {
    final isOidc = authMethod.contains('OIDC');
    if (authMethod != 'QR' && !isOidc) {
      final approvedUserAgent =
          log.detailMap['approved_user_agent']?.toString() ?? '';
      final approvedIp = log.detailMap['approved_ip']?.toString() ?? '';
      final hasApproverMeta =
          approvedUserAgent.isNotEmpty || approvedIp.isNotEmpty;
      if (!authMethod.startsWith('링크') || !hasApproverMeta) {
        return _selectableText(
          tr(
            'msg.userfront.dashboard.auth_method',
            params: {'method': authMethod},
          ),
        );
      }
      final deviceLabel = _deviceLabelFromUserAgent(approvedUserAgent);
      final tooltip = [
        tr(
          'msg.userfront.dashboard.approved_device',
          params: {'device': deviceLabel},
        ),
        tr(
          'msg.userfront.dashboard.approved_ip',
          params: {'ip': approvedIp.isEmpty ? '-' : approvedIp},
        ),
      ].join('\n');
      return Tooltip(
        message: tooltip,
        child: _selectableText(
          tr(
            'msg.userfront.dashboard.auth_method',
            params: {'method': authMethod},
          ),
          style: const TextStyle(
            color: Colors.blueAccent,
            decoration: TextDecoration.underline,
          ),
        ),
      );
    }
    final approvedSessionId =
        (log.detailMap['approved_session_id']?.toString().trim().isNotEmpty ??
            false)
        ? log.detailMap['approved_session_id'].toString()
        : log.sessionId;
    final tooltipLabel = isOidc
        ? tr('ui.userfront.dashboard.approved_session.userfront')
        : tr('ui.userfront.dashboard.approved_session.default');
    return InkWell(
      onTap: approvedSessionId.isEmpty
          ? null
          : () async {
              await Clipboard.setData(ClipboardData(text: approvedSessionId));
              if (mounted) {
                ToastService.info(
                  tr('msg.userfront.dashboard.session_id_copied'),
                );
              }
            },
      child: Tooltip(
        message: approvedSessionId.isEmpty
            ? tr(
                'msg.userfront.dashboard.approved_session.none',
                params: {'label': tooltipLabel},
              )
            : tr(
                'msg.userfront.dashboard.approved_session.copy_tap',
                params: {'label': tooltipLabel, 'id': approvedSessionId},
              ),
        child: Text(
          tr(
            'msg.userfront.dashboard.auth_method',
            params: {
              'method': isOidc
                  ? authMethod
                  : tr('ui.common.qr', fallback: 'QR'),
            },
          ),
          style: TextStyle(
            color: approvedSessionId.isEmpty ? _ink : Colors.blueAccent,
            decoration: approvedSessionId.isEmpty
                ? null
                : TextDecoration.underline,
          ),
        ),
      ),
    );
  }

  String _appLabelForLog(AuditLogEntry log) {
    if (log.appName.isNotEmpty) {
      return log.appName;
    }
    return _appLabelForPath(log.path);
  }

  Widget _buildAppCell(AuditLogEntry log, {TextStyle? style}) {
    final label = _appLabelForLog(log);
    final clientId = log.clientId;
    final tooltip = clientId.isEmpty
        ? tr('msg.userfront.dashboard.client_id_missing')
        : _renderTranslatedText(
            'msg.userfront.dashboard.client_id',
            fallback: 'Client ID: {{id}}',
            values: {'id': clientId},
          );
    final baseStyle = style ?? const TextStyle();
    final emphasisStyle = clientId.isEmpty
        ? baseStyle
        : baseStyle.copyWith(
            color: Colors.blueAccent,
            decoration: TextDecoration.underline,
          );
    return Tooltip(
      message: tooltip,
      child: _selectableText(label, style: emphasisStyle),
    );
  }

  String _appLabelForPath(String path) {
    if (path.startsWith('/api/v1/auth')) {
      return tr('ui.userfront.app_label.baron');
    }
    if (path.startsWith('/api/v1/user')) {
      return tr('ui.userfront.app_label.baron');
    }
    if (path.startsWith('/api/v1/dev')) {
      return tr('ui.userfront.app_label.dev_console', fallback: 'Dev Console');
    }
    if (path.startsWith('/api/v1/admin')) {
      return tr(
        'ui.userfront.app_label.admin_console',
        fallback: 'Admin Console',
      );
    }
    return tr('ui.userfront.app_label.baron');
  }

  @override
  Widget build(BuildContext context) {
    try {
      if (!_isLoggedIn()) {
        _redirectToSignin();
        return const SizedBox.shrink();
      }
      final isWide = MediaQuery.of(context).size.width >= sideMenuBreakpoint;
      final profileState = ref.watch(profileProvider);
      final profile = profileState.value;
      final timelineState = ref.watch(authTimelineProvider);
      final userName = (profile?.name.trim().isNotEmpty ?? false)
          ? profile!.name
          : (profile?.email.trim().isNotEmpty ?? false)
          ? profile!.email
          : (profile?.phone.trim().isNotEmpty ?? false)
          ? profile!.phone
          : tr('ui.userfront.profile.user_fallback', fallback: 'User');
      final departmentValue =
          profile?.tenant?.name ?? profile?.department ?? '';
      final department = departmentValue.isNotEmpty
          ? departmentValue
          : tr('ui.userfront.profile.department_empty');
      final sessionIssuedAt = resolveDashboardSessionIssuedAt(
        token: AuthTokenStore.getToken(),
        profile: profile,
      );

      return Scaffold(
        backgroundColor: _subtle,
        appBar: AppBar(
          leading: isWide
              ? IconButton(
                  icon: Icon(
                    _isDesktopSideMenuOpen ? Icons.menu_open : Icons.menu,
                  ),
                  tooltip: _isDesktopSideMenuOpen
                      ? tr('ui.common.collapse')
                      : '펼치기',
                  onPressed: () {
                    setState(() {
                      _isDesktopSideMenuOpen = !_isDesktopSideMenuOpen;
                    });
                  },
                )
              : Builder(
                  builder: (context) => IconButton(
                    icon: const Icon(Icons.menu),
                    tooltip: MaterialLocalizations.of(
                      context,
                    ).openAppDrawerTooltip,
                    onPressed: () => Scaffold.of(context).openDrawer(),
                  ),
                ),
          title: Text(
            tr('ui.userfront.app_title'),
            style: const TextStyle(fontWeight: FontWeight.bold),
          ),
          actions: [
            const ThemeToggleButton(compact: true),
            IconButton(
              icon: const Icon(Icons.person_outline),
              tooltip: tr('ui.userfront.nav.profile'),
              onPressed: () => context.push('/profile'),
            ),
            IconButton(
              icon: const Icon(Icons.qr_code_scanner),
              tooltip: tr('ui.userfront.nav.qr_scan'),
              onPressed: _onScanQR,
            ),
            IconButton(
              icon: const Icon(Icons.logout),
              tooltip: tr('ui.userfront.nav.logout'),
              onPressed: _logout,
            ),
          ],
        ),
        drawer: isWide
            ? null
            : Drawer(child: _buildSideMenu(context, closeOnTap: true)),
        body: Row(
          children: [
            if (isWide && _isDesktopSideMenuOpen)
              SizedBox(
                width: 240,
                child: _buildSideMenu(context, closeOnTap: false),
              ),
            Expanded(
              child: RefreshIndicator(
                onRefresh: _refreshAll,
                child: LayoutBuilder(
                  builder: (context, constraints) {
                    final timelineWide = constraints.maxWidth >= 900;
                    final isMobile = constraints.maxWidth < 600;
                    return SingleChildScrollView(
                      controller: _pageScrollController,
                      physics: const AlwaysScrollableScrollPhysics(),
                      child: Padding(
                        padding: const EdgeInsets.all(24),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            if (!isMobile) ...[
                              _buildHeaderCard(
                                userName,
                                department,
                                sessionIssuedAt,
                              ),
                              const SizedBox(height: 28),
                            ],
                            _buildSectionTitle(
                              tr('ui.userfront.sections.apps'),
                              tr('msg.userfront.sections.apps_subtitle'),
                            ),
                            const SizedBox(height: 12),
                            _buildActivitySection(isMobile),
                            const SizedBox(height: 28),
                            _buildSectionTitle(
                              tr('ui.userfront.sections.audit'),
                              tr('msg.userfront.sections.audit_subtitle'),
                            ),
                            const SizedBox(height: 12),
                            _buildAccessHistory(timelineState, timelineWide),
                          ],
                        ),
                      ),
                    );
                  },
                ),
              ),
            ),
          ],
        ),
      );
    } catch (error, stackTrace) {
      AuthProxyService.logError(
        'DASHBOARD_RENDER_ERROR: $error\nuri=${Uri.base}',
        error: error,
        stackTrace: stackTrace,
      );
      return Scaffold(
        backgroundColor: _subtle,
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(24),
            child: Text(
              tr(
                'msg.userfront.dashboard.render_error',
                fallback: '대시보드 렌더링 중 오류가 발생했습니다. 다시 시도해 주세요.',
              ),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      );
    }
  }

  Widget _buildHeaderCard(
    String userName,
    String department,
    DateTime? issuedAt,
  ) {
    final sessionLabel = issuedAt != null
        ? _formatDateTime(issuedAt)
        : tr('ui.userfront.session.unknown');
    final infoColumn = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          _renderTranslatedText(
            'msg.userfront.greeting',
            fallback: 'Hello, {{name}}.',
            values: {'name': userName},
          ),
          style: TextStyle(
            fontSize: 22,
            fontWeight: FontWeight.bold,
            color: _ink,
          ),
        ),
        const SizedBox(height: 6),
        Text(
          department,
          style: TextStyle(color: Colors.grey[600], fontSize: 14),
        ),
        const SizedBox(height: 16),
        Wrap(
          spacing: 8,
          runSpacing: 8,
          children: [
            _buildInfoChip(
              Icons.verified_user,
              tr('ui.userfront.session.active'),
            ),
            _buildInfoChip(Icons.lock_outline, _authMethodLabel()),
            _buildInfoChip(Icons.access_time, sessionLabel),
          ],
        ),
      ],
    );

    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        color: _surface,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: _border),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 10),
            blurRadius: 18,
            offset: const Offset(0, 8),
          ),
        ],
      ),
      child: infoColumn,
    );
  }

  Widget _buildSectionTitle(String title, String subtitle) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        Text(
          title,
          style: TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.w700,
            color: _ink,
          ),
        ),
        const SizedBox(width: 12),
        Text(subtitle, style: TextStyle(fontSize: 13, color: Colors.grey[600])),
      ],
    );
  }

  String _sessionDisplayLabel(UserSessionSummary session) {
    if (session.userAgent.trim().isNotEmpty) {
      return _sessionUserAgentLabel(session.userAgent);
    }
    return tr('ui.userfront.dashboard.sessions.unknown_device');
  }

  String _sessionUserAgentLabel(String userAgent) {
    final lower = userAgent.toLowerCase();
    if (lower.isEmpty) {
      return tr('ui.userfront.dashboard.sessions.unknown_device');
    }
    if (_looksLikeInternalUserAgent(lower)) {
      return '';
    }
    if (lower.contains('iphone') || lower.contains('ios')) {
      return tr('ui.userfront.device.ios');
    }
    if (lower.contains('android')) {
      return tr('ui.userfront.device.android');
    }
    if (lower.contains('windows')) {
      return tr('ui.userfront.device.windows', fallback: 'Desktop(Windows)');
    }
    if (lower.contains('mac os') || lower.contains('macintosh')) {
      return tr('ui.userfront.device.macos', fallback: 'Desktop(macOS)');
    }
    if (lower.contains('linux')) {
      return tr('ui.userfront.device.linux');
    }
    return userAgent;
  }

  String _sessionBrowserLabel(String userAgent) {
    if (userAgent == headlessServerUserAgentSentinel) {
      return '';
    }
    final lower = userAgent.toLowerCase();
    if (lower.isEmpty || _looksLikeInternalUserAgent(lower)) {
      return '';
    }
    if (lower.contains('edg/')) {
      return 'Edge';
    }
    if (lower.contains('chrome/') && !lower.contains('edg/')) {
      return 'Chrome';
    }
    if (lower.contains('firefox/')) {
      return 'Firefox';
    }
    if (lower.contains('safari/') && !lower.contains('chrome/')) {
      return 'Safari';
    }
    if (lower.contains('samsungbrowser/')) {
      return 'Samsung Internet';
    }
    if (lower.contains('flutter')) {
      return 'Flutter';
    }
    return '';
  }

  bool _looksLikeInternalUserAgent(String userAgent) {
    return userAgent.startsWith('go-http-client/') ||
        userAgent.startsWith('fasthttp') ||
        userAgent.startsWith('fiber');
  }

  Widget _buildInfoChip(IconData icon, String label) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: _subtle,
        borderRadius: BorderRadius.circular(999),
        border: Border.all(color: _border),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 16, color: _ink),
          const SizedBox(width: 6),
          Text(
            label,
            style: TextStyle(
              fontSize: 12,
              color: _ink,
              fontWeight: FontWeight.w600,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildActivitySection(bool isMobile) {
    final linkedRpsState = ref.watch(linkedRpsProvider);

    return linkedRpsState.when(
      data: (linkedRps) {
        final activities = _buildActivityItems(linkedRps);

        if (activities.isEmpty) {
          return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                tr('msg.userfront.dashboard.activities.empty'),
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[700],
                  fontWeight: FontWeight.w600,
                ),
              ),
              const SizedBox(height: 6),
              Text(
                tr('msg.userfront.dashboard.activities.empty_detail'),
                style: TextStyle(fontSize: 12, color: Colors.grey[600]),
              ),
            ],
          );
        }
        return _buildActivityGrid(activities, isMobile);
      },
      loading: () => const SizedBox(
        height: 100,
        child: Center(child: CircularProgressIndicator()),
      ),
      error: (error, stack) => Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            tr('msg.userfront.dashboard.activities.error'),
            style: TextStyle(fontSize: 12, color: Colors.grey[600]),
          ),
          const SizedBox(height: 8),
          TextButton(
            onPressed: () => ref.read(linkedRpsProvider.notifier).refresh(),
            child: Text(tr('ui.common.retry')),
          ),
        ],
      ),
    );
  }

  List<_ActivityItem> _buildActivityItems(List<LinkedRp> linkedRps) {
    final items = <_ActivityItem>[];
    for (final rp in linkedRps) {
      final normalizedStatus = rp.status.toLowerCase();
      // status가 'inactive'로 내려올 수 있으므로 이를 반영
      final isActiveInApi =
          normalizedStatus == 'active' || normalizedStatus == '';
      final isRevoked = !isActiveInApi;

      final lastAuthAt = rp.lastAuthenticatedAt;
      final lastAuthLabel = lastAuthAt != null
          ? _formatDateTime(lastAuthAt)
          : tr('ui.userfront.dashboard.activity.linked');

      final statusCode = isRevoked ? 'revoked' : 'active';
      final name = rp.name.isNotEmpty ? rp.name : rp.id;

      items.add(
        _ActivityItem(
          clientId: rp.id,
          appName: name,
          logo: rp.logo.trim(),
          lastAuthAt: lastAuthLabel,
          status: statusCode,
          scopes: rp.scopes,
          isRevoked: isRevoked,
          onRevoke: isRevoked ? null : () => _onRevokeLink(rp.id, name),
          url: rp.url,
          launchUrl: resolveLinkedRpLaunchUrl(rp),
          autoLoginSupported: rp.autoLoginSupported,
          lastAuthDateTime: rp.lastAuthenticatedAt,
        ),
      );
    }

    // 정렬 로직 적용: 활성 우선 -> 최근 인증 최신순 -> 비활성
    items.sort((a, b) {
      final aActive = a.status == 'active';
      final bActive = b.status == 'active';

      if (aActive && !bActive) return -1;
      if (!aActive && bActive) return 1;

      // 둘 다 활성이거나 둘 다 비활성인 경우 최근 인증순 내림차순
      final aLastAuth = a.lastAuthDateTime;
      final bLastAuth = b.lastAuthDateTime;
      if (aLastAuth != null && bLastAuth != null) {
        return bLastAuth.compareTo(aLastAuth);
      }
      if (a.lastAuthDateTime != null) return -1;
      if (b.lastAuthDateTime != null) return 1;

      return 0;
    });

    return items;
  }

  Widget _buildActivityGrid(List<_ActivityItem> activities, bool isMobile) {
    if (activities.isEmpty) return const SizedBox.shrink();

    return LayoutBuilder(
      builder: (context, constraints) {
        final maxWidth = constraints.maxWidth;

        final crossAxisCount = _dashboardCardColumnCount(maxWidth);

        // 초기 표시 개수는 한 줄에 표시되는 개수와 동일하게 설정 (요청에 따라 유동적 조절 가능)
        final int initialVisibleCount = crossAxisCount;
        final shouldShowToggle = activities.length > initialVisibleCount;

        List<_ActivityItem> visibleActivities;
        if (_showAllActivities) {
          visibleActivities = activities;
        } else {
          visibleActivities = activities.take(initialVisibleCount).toList();
        }

        final cardWidth = _dashboardCardWidth(maxWidth, crossAxisCount);

        return Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Wrap(
              spacing: _dashboardCardSpacing,
              runSpacing: _dashboardCardSpacing,
              children: visibleActivities.map((item) {
                return SizedBox(
                  width: cardWidth,
                  child: _buildActivityCard(item, cardWidth: cardWidth),
                );
              }).toList(),
            ),
            if (shouldShowToggle)
              Padding(
                padding: const EdgeInsets.only(top: 16),
                child: Align(
                  alignment: Alignment.centerRight,
                  child: TextButton.icon(
                    onPressed: () => setState(
                      () => _showAllActivities = !_showAllActivities,
                    ),
                    icon: Icon(
                      _showAllActivities ? Icons.keyboard_arrow_up : Icons.add,
                      size: 18,
                      color: _showAllActivities
                          ? Colors.grey
                          : Colors.blueAccent,
                    ),
                    label: Text(
                      _showAllActivities
                          ? tr('ui.common.collapse')
                          : tr('ui.common.show_more'),
                      style: TextStyle(
                        color: _showAllActivities
                            ? Colors.grey
                            : Colors.blueAccent,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),
                ),
              ),
          ],
        );
      },
    );
  }

  Widget _buildActivityCard(_ActivityItem item, {double? cardWidth}) {
    final isActive = item.status == 'active';
    final statusColor = _activityStatusColor(item.status);
    final borderColor = isActive
        ? Colors.green.withValues(alpha: 128)
        : _border;
    final borderWidth = isActive ? 1.5 : 1.0;

    // 활성 상태면 클릭 가능 (URL 유무와 관계없이)
    final isClickable = isActive;

    // 카드 컨텐츠
    final cardContent = Container(
      width: cardWidth ?? 260,
      padding: const EdgeInsets.all(14),
      decoration: BoxDecoration(
        color: _surface,
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: borderColor, width: borderWidth),
        boxShadow: isActive
            ? [
                BoxShadow(
                  color: Colors.green.withValues(alpha: 13),
                  blurRadius: 10,
                  offset: const Offset(0, 4),
                ),
              ]
            : null,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          _buildActivityCardHeader(item, statusColor),
          const SizedBox(height: 10),
          Text(
            tr('ui.userfront.dashboard.last_auth_label'),
            style: TextStyle(fontSize: 12, color: Colors.grey[600]),
          ),
          const SizedBox(height: 4),
          Text(
            item.lastAuthAt,
            style: TextStyle(
              fontSize: 13,
              fontWeight: FontWeight.w600,
              color: _ink,
            ),
          ),
          if (item.autoLoginSupported) ...[
            const SizedBox(height: 8),
            Text(
              tr(
                'msg.userfront.dashboard.auto_login_supported',
                fallback: '연동앱 클릭 시 별도 로그인 없이 로그인할 수 있습니다.',
              ),
              style: TextStyle(fontSize: 12, color: Colors.green[700]),
            ),
          ],
          const SizedBox(height: 14),
          Row(
            children: [
              Expanded(
                child: OutlinedButton(
                  onPressed: () => _showRpDetails(item),
                  style: OutlinedButton.styleFrom(
                    foregroundColor: _ink,
                    side: BorderSide(color: _border),
                    padding: const EdgeInsets.symmetric(vertical: 7),
                  ),
                  child: Text(
                    tr('ui.common.details'),
                    style: const TextStyle(fontSize: 13),
                  ),
                ),
              ),
              const SizedBox(width: 8),
              Expanded(
                child: OutlinedButton(
                  onPressed: (_isRevoking || item.isRevoked)
                      ? null
                      : item.onRevoke,
                  style: OutlinedButton.styleFrom(
                    foregroundColor: item.isRevoked
                        ? Colors.grey
                        : Colors.redAccent,
                    side: BorderSide(
                      color: item.isRevoked ? Colors.grey : Colors.redAccent,
                      width: 0.5,
                    ),
                    padding: const EdgeInsets.symmetric(vertical: 7),
                  ),
                  child: _isRevoking && !item.isRevoked
                      ? const SizedBox(
                          width: 14,
                          height: 14,
                          child: CircularProgressIndicator(
                            strokeWidth: 2,
                            color: Colors.redAccent,
                          ),
                        )
                      : _singleLineText(
                          item.isRevoked
                              ? tr('ui.userfront.dashboard.status.revoked')
                              : tr('ui.userfront.dashboard.revoke.title'),
                          style: const TextStyle(fontSize: 13),
                        ),
                ),
              ),
            ],
          ),
        ],
      ),
    );

    // Opacity 적용
    final opaqueCard = Opacity(
      opacity: item.isRevoked ? 0.6 : 1.0,
      child: cardContent,
    );

    // 클릭 가능한 경우 InkWell로 감싸기
    if (isClickable) {
      return MouseRegion(
        cursor: SystemMouseCursors.click,
        child: GestureDetector(
          onTap: () async {
            final itemUrl = item.launchUrl;
            if (itemUrl != null && itemUrl.isNotEmpty) {
              final uri = Uri.parse(itemUrl);
              final canOpen = await canLaunchUrl(uri);
              if (!mounted) return;
              if (canOpen) {
                await launchUrl(uri);
                return;
              }
              ToastService.error(tr('msg.userfront.dashboard.link_open_error'));
            } else {
              if (!mounted) return;
              ToastService.info(tr('msg.userfront.dashboard.link_missing'));
            }
          },
          child: opaqueCard,
        ),
      );
    }

    return opaqueCard;
  }

  Widget _buildActivityCardHeader(_ActivityItem item, Color statusColor) {
    final statusBadge = Container(
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      decoration: BoxDecoration(
        color: statusColor,
        borderRadius: BorderRadius.circular(999),
      ),
      child: Text(
        item.status == 'active'
            ? tr('ui.userfront.dashboard.activity.linked')
            : tr('ui.userfront.dashboard.status.revoked'),
        style: const TextStyle(
          fontSize: 11,
          color: Colors.white,
          fontWeight: FontWeight.w600,
        ),
      ),
    );

    return SizedBox(
      height: 40,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          if (item.logo.isNotEmpty) ...[
            _buildActivityLogo(item.logo),
            const SizedBox(width: 10),
          ],
          Expanded(
            child: Align(
              alignment: Alignment.centerLeft,
              child: Text(
                item.appName,
                maxLines: 2,
                overflow: TextOverflow.ellipsis,
                style: TextStyle(
                  fontSize: 15,
                  fontWeight: FontWeight.w600,
                  color: _ink,
                  height: 1.25,
                ),
              ),
            ),
          ),
          const SizedBox(width: 8),
          statusBadge,
        ],
      ),
    );
  }

  Widget _buildActivityLogo(String logoUrl) {
    return SizedBox(
      width: 40,
      height: 40,
      child: _buildActivityLogoImage(logoUrl),
    );
  }

  Widget _buildActivityLogoImage(String logoUrl) {
    final isSvg = _isSvgLogoUrl(logoUrl);
    return isSvg
        ? SvgPicture.network(
            logoUrl,
            fit: BoxFit.contain,
            placeholderBuilder: (context) => _buildActivityLogoLoading(),
          )
        : Image.network(
            logoUrl,
            fit: BoxFit.contain,
            errorBuilder: (context, error, stackTrace) {
              return _buildActivityLogoFallback();
            },
            loadingBuilder: (context, child, loadingProgress) {
              if (loadingProgress == null) {
                return child;
              }
              return _buildActivityLogoLoading();
            },
          );
  }

  bool _isSvgLogoUrl(String logoUrl) {
    final normalized = logoUrl.trim().toLowerCase();
    if (normalized.isEmpty) {
      return false;
    }
    final uri = Uri.tryParse(normalized);
    final path = uri?.path.toLowerCase() ?? normalized;
    return path.endsWith('.svg');
  }

  Widget _buildActivityLogoLoading() {
    return Center(
      child: SizedBox(
        width: 16,
        height: 16,
        child: CircularProgressIndicator(
          strokeWidth: 2,
          color: Colors.grey[400],
        ),
      ),
    );
  }

  Widget _buildActivityLogoFallback() {
    return Icon(Icons.apps_rounded, size: 20, color: Colors.grey[500]);
  }

  Widget _buildAccessHistory(AuthTimelineState state, bool isWide) {
    final sessionsState = ref.watch(userSessionsProvider);
    if (state.isLoading && state.items.isEmpty) {
      return _buildHistoryContainer(
        child: const SizedBox(
          height: 120,
          child: Center(child: CircularProgressIndicator()),
        ),
      );
    }

    if (state.error != null && state.items.isEmpty) {
      return _buildHistoryContainer(
        child: SizedBox(
          height: 120,
          child: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(tr('msg.userfront.dashboard.audit_load_error')),
                const SizedBox(height: 8),
                TextButton(
                  onPressed: () =>
                      ref.read(authTimelineProvider.notifier).refresh(),
                  child: Text(tr('ui.common.retry')),
                ),
              ],
            ),
          ),
        ),
      );
    }

    if (sessionsState.isLoading && !sessionsState.hasValue) {
      return _buildHistoryContainer(
        child: const SizedBox(
          height: 120,
          child: Center(child: CircularProgressIndicator()),
        ),
      );
    }

    if (sessionsState.hasError && !sessionsState.hasValue) {
      return _buildHistoryContainer(
        child: SizedBox(
          height: 120,
          child: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(tr('msg.userfront.dashboard.sessions.error')),
                const SizedBox(height: 8),
                TextButton(
                  onPressed: () =>
                      ref.read(userSessionsProvider.notifier).refresh(),
                  child: Text(tr('ui.common.retry')),
                ),
              ],
            ),
          ),
        ),
      );
    }

    final sessions = sessionsState is AsyncData<List<UserSessionSummary>>
        ? sessionsState.value
        : const <UserSessionSummary>[];
    final Map<String, UserSessionSummary> sessionById = {
      for (final session in sessions) session.sessionId.trim(): session,
    };
    final filteredItems = state.items.where((log) {
      if (!_showActiveSessionsOnly) {
        return true;
      }
      final status = _historySessionStatusForLog(log, sessionById);
      return status != _HistorySessionStatus.inactive;
    }).toList();

    if (filteredItems.isEmpty) {
      return _buildHistoryContainer(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildHistoryHeader(),
            const SizedBox(height: 20),
            Center(
              child: Padding(
                padding: const EdgeInsets.symmetric(vertical: 16),
                child: Text(
                  _showActiveSessionsOnly
                      ? tr('msg.userfront.audit.filtered_empty')
                      : tr('msg.userfront.dashboard.audit_empty'),
                  style: TextStyle(color: Colors.grey[600]),
                  textAlign: TextAlign.center,
                ),
              ),
            ),
          ],
        ),
      );
    }

    if (isWide) {
      return _buildHistoryTable(state, filteredItems, sessionById);
    }
    return _buildHistoryList(state, filteredItems, sessionById);
  }

  Widget _buildHistoryHeader() {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                tr('ui.userfront.audit.filter.title'),
                style: TextStyle(
                  fontSize: 15,
                  fontWeight: FontWeight.w700,
                  color: _ink,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                tr('msg.userfront.audit.filter.description'),
                style: TextStyle(fontSize: 12, color: Colors.grey[600]),
              ),
            ],
          ),
        ),
        const SizedBox(width: 16),
        Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              tr('ui.userfront.audit.filter.toggle_label'),
              style: TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.w600,
                color: _ink,
              ),
            ),
            const SizedBox(width: 2),
            Transform.scale(
              scale: 0.84,
              alignment: Alignment.centerRight,
              child: Switch(
                materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
                value: _showActiveSessionsOnly,
                onChanged: (value) {
                  setState(() {
                    _showActiveSessionsOnly = value;
                  });
                },
              ),
            ),
          ],
        ),
      ],
    );
  }

  Widget _buildHistoryContainer({required Widget child}) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: _surface,
        borderRadius: BorderRadius.circular(14),
        border: Border.all(color: _border),
      ),
      child: child,
    );
  }

  _HistorySessionStatus _historySessionStatusForLog(
    AuditLogEntry log,
    Map<String, UserSessionSummary> sessionById,
  ) {
    final sessionId = log.sessionId.trim();
    if (sessionId.isEmpty) {
      return _HistorySessionStatus.inactive;
    }
    final session = sessionById[sessionId];
    if (session == null) {
      return _HistorySessionStatus.inactive;
    }
    if (session.isCurrent) {
      return _HistorySessionStatus.current;
    }
    if (session.isActive) {
      return _HistorySessionStatus.active;
    }
    return _HistorySessionStatus.inactive;
  }

  String _historySessionStatusLabel(_HistorySessionStatus status) {
    switch (status) {
      case _HistorySessionStatus.current:
        return tr('ui.userfront.dashboard.sessions.current_badge');
      case _HistorySessionStatus.active:
        return tr('ui.userfront.dashboard.sessions.active_badge');
      case _HistorySessionStatus.inactive:
        return tr('ui.common.status.inactive');
    }
  }

  Color _historySessionStatusColor(_HistorySessionStatus status) {
    switch (status) {
      case _HistorySessionStatus.current:
        return Colors.blueGrey;
      case _HistorySessionStatus.active:
        return Colors.green;
      case _HistorySessionStatus.inactive:
        return Colors.grey;
    }
  }

  Widget _buildHistoryStatusBadge(_HistorySessionStatus status) {
    return SizedBox(
      width: _historyStatusColumnWidth,
      child: Center(
        child: Container(
          padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
          decoration: BoxDecoration(
            color: _historySessionStatusColor(status),
            borderRadius: BorderRadius.circular(999),
          ),
          child: Text(
            _historySessionStatusLabel(status),
            style: const TextStyle(
              fontSize: 11,
              color: Colors.white,
              fontWeight: FontWeight.w600,
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildHistorySessionActionCell(UserSessionSummary? session) {
    if (session == null) {
      return SizedBox(
        width: _historyActionColumnWidth,
        child: Center(
          child: _selectableText(tr('ui.common.hyphen', fallback: '-')),
        ),
      );
    }
    final isCurrent = session.isCurrent;
    final canRevoke =
        !isCurrent && _revokingSessionId == null && session.isActive;
    return SizedBox(
      width: _historyActionColumnWidth,
      child: OutlinedButton(
        onPressed: canRevoke ? () => _onRevokeSession(session) : null,
        style: OutlinedButton.styleFrom(
          foregroundColor: canRevoke ? Colors.redAccent : Colors.grey,
          side: BorderSide(
            color: canRevoke ? Colors.redAccent : Colors.grey,
            width: 0.6,
          ),
          padding: const EdgeInsets.symmetric(vertical: 10),
        ),
        child: _revokingSessionId == session.sessionId
            ? const SizedBox(
                width: 14,
                height: 14,
                child: CircularProgressIndicator(
                  strokeWidth: 2,
                  color: Colors.redAccent,
                ),
              )
            : Text(
                isCurrent
                    ? tr('ui.userfront.dashboard.sessions.current_disabled')
                    : session.isActive
                    ? tr('ui.userfront.dashboard.sessions.revoke.action')
                    : tr('ui.common.hyphen', fallback: '-'),
              ),
      ),
    );
  }

  int _dashboardCardColumnCount(double maxWidth) {
    if (maxWidth > 1200) {
      return 4;
    }
    if (maxWidth > 800) {
      return 3;
    }
    return 2;
  }

  double _dashboardCardWidth(double maxWidth, int crossAxisCount) {
    return math.min(
      (maxWidth - (_dashboardCardSpacing * (crossAxisCount - 1))) /
          crossAxisCount,
      _dashboardCardMaxWidth,
    );
  }

  Color _activityStatusColor(String status) {
    return status == 'active' ? Colors.green : Colors.grey;
  }

  Widget _buildCenteredHistoryHeader(String label, {double? width}) {
    return SizedBox(
      width: width,
      child: Center(child: Text(label, textAlign: TextAlign.center)),
    );
  }

  Widget _buildCenteredHistoryCell(Widget child, {double? width}) {
    return SizedBox(
      width: width,
      child: Center(child: child),
    );
  }

  Widget _buildHistoryTable(
    AuthTimelineState state,
    List<AuditLogEntry> items,
    Map<String, UserSessionSummary> sessionById,
  ) {
    return _buildHistoryContainer(
      child: Column(
        children: [
          _buildHistoryHeader(),
          const SizedBox(height: 16),
          LayoutBuilder(
            builder: (context, constraints) {
              final sessionColumnWidth = _historySessionColumnWidth(
                constraints.maxWidth,
              );
              return SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: ConstrainedBox(
                  constraints: BoxConstraints(minWidth: constraints.maxWidth),
                  child: DataTable(
                    columnSpacing: 16,
                    horizontalMargin: 12,
                    columns: [
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr(
                            'ui.userfront.audit.table.session_id',
                            fallback: 'Session ID',
                          ),
                          width: sessionColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.date'),
                          width: _historyDateColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.app'),
                          width: _historyAppColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.ip', fallback: 'IP'),
                          width: _historyIpColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.device'),
                          width: _historyDeviceColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.browser'),
                          width: _historyBrowserColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.auth_method'),
                          width: _historyAuthMethodColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.result'),
                          width: _historyResultColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.status'),
                          width: _historyStatusColumnWidth,
                        ),
                      ),
                      DataColumn(
                        label: _buildCenteredHistoryHeader(
                          tr('ui.userfront.audit.table.action'),
                          width: _historyActionColumnWidth,
                        ),
                      ),
                    ],
                    rows: items.map((log) {
                      final matchedSession = sessionById[log.sessionId.trim()];
                      final sessionStatus = _historySessionStatusForLog(
                        log,
                        sessionById,
                      );
                      final statusLabel = log.status == 'success'
                          ? tr('ui.common.status.success')
                          : tr('ui.common.status.failure');
                      final statusColor = log.status == 'success'
                          ? Colors.green
                          : Colors.redAccent;
                      final authMethod = log.authMethod.isNotEmpty
                          ? log.authMethod
                          : _authMethodLabel();
                      final preferredUserAgent = preferredAuditLogUserAgent(
                        log,
                      );
                      final deviceLabel = _deviceLabelFromUserAgent(
                        preferredUserAgent,
                      );
                      final browserLabel = _sessionBrowserLabel(
                        preferredUserAgent,
                      );
                      return DataRow(
                        cells: [
                          DataCell(
                            _buildCenteredHistoryCell(
                              _buildHistorySessionIdCell(
                                log.sessionId.isEmpty
                                    ? tr('ui.common.hyphen', fallback: '-')
                                    : log.sessionId,
                                sessionColumnWidth,
                              ),
                              width: sessionColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _selectableText(_formatDateTime(log.timestamp)),
                              width: _historyDateColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _buildAppCell(log),
                              width: _historyAppColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _selectableText(
                                log.ipAddress.isEmpty
                                    ? tr('ui.common.hyphen', fallback: '-')
                                    : log.ipAddress,
                              ),
                              width: _historyIpColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _singleLineText(deviceLabel),
                              width: _historyDeviceColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _selectableText(
                                browserLabel.isEmpty
                                    ? tr('ui.common.hyphen', fallback: '-')
                                    : browserLabel,
                              ),
                              width: _historyBrowserColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _buildAuthMethodCell(log, authMethod),
                              width: _historyAuthMethodColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _selectableText(
                                statusLabel,
                                style: TextStyle(
                                  color: statusColor,
                                  fontWeight: FontWeight.w600,
                                ),
                              ),
                              width: _historyResultColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _buildHistoryStatusBadge(sessionStatus),
                              width: _historyStatusColumnWidth,
                            ),
                          ),
                          DataCell(
                            _buildCenteredHistoryCell(
                              _buildHistorySessionActionCell(matchedSession),
                              width: _historyActionColumnWidth,
                            ),
                          ),
                        ],
                      );
                    }).toList(),
                  ),
                ),
              );
            },
          ),
          _buildHistoryFooter(state),
        ],
      ),
    );
  }

  double _historySessionColumnWidth(double maxWidth) {
    return math.min(
      200.0,
      math.max(
        _historySessionMinWidth,
        maxWidth - _historyOtherColumnsBaselineWidth,
      ),
    );
  }

  String _compactSessionId(String sessionId) {
    final parts = sessionId.split('-');
    if (parts.length >= 4) {
      return '${parts.take(3).join('-')}-...';
    }
    if (sessionId.length <= _historySessionMinVisibleChars) {
      return sessionId;
    }
    return '${sessionId.substring(0, _historySessionMinVisibleChars)}...';
  }

  Widget _buildHistorySessionIdCell(String sessionId, double columnWidth) {
    final displayText = _compactSessionId(sessionId);
    final textWidget = Text(
      displayText,
      maxLines: 1,
      softWrap: false,
      overflow: TextOverflow.ellipsis,
      textAlign: TextAlign.center,
    );

    if (displayText == sessionId || sessionId.isEmpty) {
      return textWidget;
    }
    return Tooltip(message: sessionId, child: textWidget);
  }

  Widget _buildHistoryList(
    AuthTimelineState state,
    List<AuditLogEntry> items,
    Map<String, UserSessionSummary> sessionById,
  ) {
    return _buildHistoryContainer(
      child: Column(
        children: [
          _buildHistoryHeader(),
          const SizedBox(height: 16),
          for (final log in items)
            Container(
              margin: const EdgeInsets.only(bottom: 12),
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: _subtle,
                borderRadius: BorderRadius.circular(12),
                border: Border.all(color: _border),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      _buildHistoryStatusBadge(
                        _historySessionStatusForLog(log, sessionById),
                      ),
                      const Spacer(),
                    ],
                  ),
                  const SizedBox(height: 8),
                  Row(
                    children: [
                      Expanded(
                        child: _buildAppCell(
                          log,
                          style: TextStyle(
                            fontWeight: FontWeight.w600,
                            color: _ink,
                          ),
                        ),
                      ),
                      _selectableText(
                        log.status == 'success'
                            ? tr('ui.common.status.success')
                            : tr('ui.common.status.failure'),
                        style: TextStyle(
                          color: log.status == 'success'
                              ? Colors.green
                              : Colors.redAccent,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 6),
                  _selectableText(
                    _renderTranslatedText(
                      'msg.userfront.audit.session_id',
                      fallback: 'Session ID: {{value}}',
                      values: {
                        'value': log.sessionId.isEmpty
                            ? tr('ui.common.hyphen', fallback: '-')
                            : log.sessionId,
                      },
                    ),
                  ),
                  _selectableText(
                    tr(
                      'msg.userfront.audit.date',
                      params: {'value': _formatDateTime(log.timestamp)},
                    ),
                  ),
                  _selectableText(
                    tr(
                      'msg.userfront.audit.ip',
                      params: {
                        'value': log.ipAddress.isEmpty
                            ? tr('ui.common.hyphen', fallback: '-')
                            : log.ipAddress,
                      },
                    ),
                  ),
                  _selectableText(
                    tr(
                      'msg.userfront.audit.device',
                      params: {
                        'value': _deviceLabelFromUserAgent(
                          preferredAuditLogUserAgent(log),
                        ),
                      },
                    ),
                  ),
                  _selectableText(
                    tr(
                      'msg.userfront.audit.browser',
                      params: {
                        'value':
                            _sessionBrowserLabel(
                              preferredAuditLogUserAgent(log),
                            ).isEmpty
                            ? tr('ui.common.hyphen', fallback: '-')
                            : _sessionBrowserLabel(
                                preferredAuditLogUserAgent(log),
                              ),
                      },
                    ),
                  ),
                  _buildAuthMethodLine(
                    log,
                    log.authMethod.isNotEmpty
                        ? log.authMethod
                        : _authMethodLabel(),
                  ),
                  _selectableText(
                    tr(
                      'msg.userfront.audit.result',
                      params: {
                        'value': log.status == 'success'
                            ? tr('ui.common.status.success')
                            : tr('ui.common.status.failure'),
                      },
                    ),
                  ),
                  _selectableText(
                    tr(
                      'msg.userfront.audit.status',
                      params: {
                        'value': _historySessionStatusLabel(
                          _historySessionStatusForLog(log, sessionById),
                        ),
                      },
                    ),
                  ),
                  const SizedBox(height: 12),
                  _buildHistorySessionActionCell(
                    sessionById[log.sessionId.trim()],
                  ),
                ],
              ),
            ),
          _buildHistoryFooter(state),
        ],
      ),
    );
  }

  Widget _buildHistoryFooter(AuthTimelineState state) {
    if (state.isLoadingMore) {
      return const Padding(
        padding: EdgeInsets.only(top: 8),
        child: Center(child: CircularProgressIndicator()),
      );
    }
    if (state.error != null) {
      return Padding(
        padding: const EdgeInsets.only(top: 8),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(tr('msg.userfront.audit.load_more_error')),
            TextButton(
              onPressed: () =>
                  ref.read(authTimelineProvider.notifier).loadMore(),
              child: Text(tr('ui.common.retry')),
            ),
          ],
        ),
      );
    }
    final nextCursor = state.nextCursor;
    if (nextCursor == null || nextCursor.isEmpty) {
      return Padding(
        padding: const EdgeInsets.only(top: 8),
        child: Text(
          tr('msg.userfront.audit.end'),
          style: TextStyle(color: Colors.grey[600], fontSize: 12),
        ),
      );
    }
    return const SizedBox.shrink();
  }

  bool _isLoggedIn() {
    final token = AuthTokenStore.getToken();
    return (token != null && token.isNotEmpty) || AuthTokenStore.usesCookie();
  }

  void _redirectToSignin() {
    if (!mounted || _redirectingToSignin) {
      return;
    }
    _redirectingToSignin = true;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) {
        return;
      }
      Uri uri;
      try {
        uri = GoRouterState.of(context).uri;
      } catch (_) {
        uri = Uri.base;
      }
      final localeCode =
          extractLocaleFromPath(uri) ?? resolvePreferredLocaleCode();
      context.go('/$localeCode/signin');
      _redirectingToSignin = false;
    });
  }

  Future<void> _bootstrapAuthAndLoad() async {
    if (!mounted || _authBootstrapInProgress) {
      return;
    }
    _authBootstrapInProgress = true;
    try {
      var authenticated = _isLoggedIn();
      if (!authenticated) {
        authenticated = await _recoverSessionFromCookie();
      }
      if (!mounted) {
        return;
      }
      if (!authenticated) {
        _redirectToSignin();
        return;
      }
    } finally {
      _authBootstrapInProgress = false;
    }
  }

  Future<bool> _recoverSessionFromCookie() async {
    try {
      await AuthProxyService.checkCookieSession();
      final provider =
          AuthTokenStore.getProvider() ??
          AuthTokenStore.getPendingProvider() ??
          'ory';
      AuthTokenStore.setCookieMode(provider: provider);
      AuthTokenStore.clearPendingProvider();
      AuthNotifier.instance.notify();
      try {
        await ref.read(profileProvider.notifier).loadProfile();
      } catch (_) {}
      return true;
    } catch (_) {
      return false;
    }
  }
}

enum _HistorySessionStatus { current, active, inactive }

class _ActivityItem {
  final String clientId;
  final String appName;
  final String logo;
  final String lastAuthAt;
  final String status;
  final String? url;
  final String? launchUrl;
  final bool autoLoginSupported;
  final List<String> scopes;
  final bool isRevoked;
  final VoidCallback? onRevoke;
  final DateTime? lastAuthDateTime;

  _ActivityItem({
    required this.clientId,
    required this.appName,
    required this.logo,
    required this.lastAuthAt,
    required this.status,
    required this.scopes,
    this.url,
    this.launchUrl,
    this.autoLoginSupported = false,
    this.isRevoked = false,
    this.onRevoke,
    this.lastAuthDateTime,
  });
}
