import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:qr_flutter/qr_flutter.dart';
import 'package:userfront/i18n.dart';
import '../../../core/widgets/language_selector.dart';
import '../../../core/widgets/theme_toggle_button.dart';
import '../../../core/services/web_auth_integration.dart';
import '../../../core/services/auth_proxy_service.dart';
import '../../../core/services/auth_token_store.dart';
import '../../../core/services/login_challenge_loop_guard.dart';
import '../../../core/i18n/locale_utils.dart';
import '../../../core/services/oidc_redirect_guard.dart';
import '../../../core/notifiers/auth_notifier.dart';
import '../domain/login_challenge_resolver.dart';
import '../domain/cookie_session_policy.dart';
import '../domain/consent_error_routing.dart';
import '../domain/login_link_route_policy.dart';
import '../domain/verification_completion_route.dart';
import '../../profile/domain/notifiers/profile_notifier.dart';
import '../../../core/services/web_window.dart';
import '../../../core/ui/toast_service.dart';

class LoginScreen extends ConsumerStatefulWidget {
  final String? verificationToken;
  final String? loginChallenge;
  final String? redirectUrl;
  final bool verificationCompleteOnly;

  const LoginScreen({
    super.key,
    this.verificationToken,
    this.loginChallenge,
    this.redirectUrl,
    this.verificationCompleteOnly = false,
  });

  @override
  ConsumerState<LoginScreen> createState() => _LoginScreenState();
}

class _LoginScreenState extends ConsumerState<LoginScreen>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  final TextEditingController _linkIdController = TextEditingController();
  final TextEditingController _passwordLoginIdController =
      TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final FocusNode _passwordFocusNode = FocusNode();
  String? _redirectUrl;
  String? _loginChallenge;
  bool _isPasswordCapsLockOn = false;
  String? _loginIdLabel;

  // QR Login Variables
  String? _qrImageBase64;
  String? _qrPendingRef;
  bool _isQrLoading = false;
  bool _qrExpired = false;
  Timer? _qrPollingTimer;
  int _qrRemainingSeconds = 0;
  Timer? _qrCountdownTimer;
  int _qrPollIntervalMs = 2000;
  final TextEditingController _shortCodePrefixController =
      TextEditingController();
  final TextEditingController _shortCodeDigitsController =
      TextEditingController();
  String? _linkPendingRef;
  String? _lastLinkLoginId;
  bool _lastLinkIsEmail = true;
  int _linkResendSeconds = 0;
  Timer? _linkResendTimer;
  int _linkExpireSeconds = 0;
  Timer? _linkExpireTimer;
  bool _linkExpired = false;
  bool _verificationOnly = false;
  bool _verificationApproved = false;
  bool _dismissedOverlays = false;
  bool _localNavigationCompleted = false;
  String? _verificationMessageKey;
  String _verificationTitleKey = 'ui.userfront.login.verification.title';
  String _verificationPageTitleKey =
      'ui.userfront.login.verification.page_title';
  String _verificationActionLabelKey =
      'ui.userfront.login.verification.action_label';
  Timer? _verificationRedirectTimer;
  bool _noticeHandled = false;
  bool _drySendEnabled = false;
  bool _oidcAutoAcceptTried = false;
  bool _verificationHandoffStarted = false;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this, initialIndex: 0);
    _tabController.addListener(_handleTabSelection);
    _drySendEnabled =
        _parseBoolParam(Uri.base.queryParameters['drySend']) &&
        !AuthProxyService.isProdEnv;
    _redirectUrl = widget.redirectUrl;
    _passwordFocusNode.addListener(_handlePasswordFocusChange);
    HardwareKeyboard.instance.addHandler(_handleHardwareKeyEvent);
    _verificationOnly =
        widget.verificationCompleteOnly || _isVerificationOnlyUri(Uri.base);

    WidgetsBinding.instance.addPostFrameCallback((_) async {
      final uri = Uri.base;

      if (_redirectUrl == null) {
        if (uri.queryParameters.containsKey('redirect_url')) {
          _redirectUrl = uri.queryParameters['redirect_url'];
        } else if (uri.queryParameters.containsKey('redirect_uri')) {
          _redirectUrl = uri.queryParameters['redirect_uri'];
        }
      }

      final challengeResolution = _resolveLoginChallenge(uri);
      _loginChallenge = challengeResolution.value;
      _logLoginChallengeDiagnostics(
        phase: 'init',
        resolution: challengeResolution,
      );
      final loginIdParam = uri.queryParameters['loginId'];
      final codeParam = uri.queryParameters['code'];
      final pendingRefParam = uri.queryParameters['pendingRef'];
      final shortCodeFromPath = extractLoginShortCode(uri);
      final hasShortCodePath = shortCodeFromPath != null;
      final acceptsVerificationPayload = isDedicatedVerificationRoute(uri);
      final waitsForVerificationHandoff =
          !acceptsVerificationPayload && hasVerificationPayload(uri);
      final hasTokenParam =
          acceptsVerificationPayload && uri.queryParameters.containsKey('t');
      final hasVerificationToken =
          widget.verificationToken != null || hasTokenParam;
      final hasLoginCode =
          acceptsVerificationPayload &&
          loginIdParam != null &&
          codeParam != null;
      final notice = uri.queryParameters['notice'];

      if (widget.verificationCompleteOnly) {
        _markVerificationApproved(
          'msg.userfront.login.verification.approved_remote',
          titleKey: 'ui.userfront.login.verification.title_remote',
          actionLabelKey: 'ui.userfront.login.verification.action_label_remote',
          onAction: _moveToSigninOrCloseVerificationWindow,
        );
        return;
      }

      if (waitsForVerificationHandoff) {
        final localeCode =
            extractLocaleFromPath(uri) ?? resolvePreferredLocaleCode();
        final target = buildDedicatedVerificationRedirect(
          uri,
          localeCode: localeCode,
        );
        if (target != null && mounted) {
          context.go(target);
          _startVerificationHandoff(Uri.parse(target));
        }
        return;
      }

      if (hasShortCodePath) {
        _verifyShortCode(shortCodeFromPath);
      }
      if (hasLoginCode) {
        _verifyLoginCode(loginIdParam, codeParam, pendingRef: pendingRefParam);
      } else if (hasVerificationToken) {
        final verificationToken =
            widget.verificationToken ?? uri.queryParameters['t'];
        if (verificationToken != null && verificationToken.isNotEmpty) {
          _verifyToken(verificationToken);
        }
      }

      if (!_noticeHandled && notice == 'qr_login_required') {
        _noticeHandled = true;
        _showInfo(tr('msg.userfront.login.qr_login_required'));
      }

      if (!_verificationOnly) {
        await _attemptOidcAutoAccept();
        if (!mounted) return;

        // Fetch Tenant Info to check for custom login ID label
        try {
          final info = await AuthProxyService.getTenantInfo();
          if (info['loginIdLabel'] != null) {
            setState(() {
              _loginIdLabel = info['loginIdLabel'];
            });
          }
        } catch (e) {
          debugPrint("[Auth] Failed to fetch tenant info: $e");
        }

        // login_challenge 흐름에서는 auto-accept에서 이미 쿠키 세션까지 확인하므로
        // 동일 프레임에서 중복 체크를 피합니다.
        if (!_hasLoginChallenge) {
          await _tryCookieSession();
        }
      }
    });
  }

  bool _isVerificationOnlyUri(Uri uri) {
    if (!isDedicatedVerificationRoute(uri) &&
        widget.verificationToken == null) {
      return false;
    }
    final loginIdParam = uri.queryParameters['loginId'];
    final codeParam = uri.queryParameters['code'];
    return widget.verificationToken != null ||
        uri.queryParameters.containsKey('t') ||
        (loginIdParam != null && codeParam != null) ||
        extractLoginShortCode(uri) != null;
  }

  void _startVerificationHandoff(Uri targetUri) {
    if (_verificationHandoffStarted) {
      return;
    }
    _verificationHandoffStarted = true;
    if (mounted) {
      setState(() {
        _verificationOnly = true;
      });
    } else {
      _verificationOnly = true;
    }

    final loginIdParam = targetUri.queryParameters['loginId'];
    final codeParam = targetUri.queryParameters['code'];
    final pendingRefParam = targetUri.queryParameters['pendingRef'];
    final tokenParam = targetUri.queryParameters['t'];

    if (loginIdParam != null && codeParam != null) {
      _verifyLoginCode(loginIdParam, codeParam, pendingRef: pendingRefParam);
      return;
    }
    if (tokenParam != null && tokenParam.isNotEmpty) {
      _verifyToken(tokenParam);
    }
  }

  void _handlePasswordFocusChange() {
    if (!mounted) {
      return;
    }
    if (_passwordFocusNode.hasFocus) {
      _syncPasswordCapsLockState();
      return;
    }
    if (_isPasswordCapsLockOn) {
      setState(() {
        _isPasswordCapsLockOn = false;
      });
    }
  }

  bool _handleHardwareKeyEvent(KeyEvent event) {
    if (_passwordFocusNode.hasFocus) {
      _syncPasswordCapsLockState();
    }
    return false;
  }

  void _syncPasswordCapsLockState() {
    final isEnabled = HardwareKeyboard.instance.lockModesEnabled.contains(
      KeyboardLockMode.capsLock,
    );
    if (!mounted || isEnabled == _isPasswordCapsLockOn) {
      return;
    }
    setState(() {
      _isPasswordCapsLockOn = isEnabled;
    });
  }

  Future<void> _tryCookieSession({bool silent = true}) async {
    if (AuthTokenStore.consumeSkipCookieSessionCheck()) {
      debugPrint(
        "[Auth] Skipping one cookie session check after verification handoff.",
      );
      return;
    }
    final loginChallenge = _loginChallenge;
    final token = AuthTokenStore.getToken();
    if (!shouldPromoteCookieSession(
      currentToken: token,
      loginChallenge: loginChallenge,
    )) {
      return;
    }
    final pendingProvider = AuthTokenStore.getPendingProvider();
    final provider = pendingProvider ?? AuthTokenStore.getProvider() ?? 'ory';

    try {
      final status = await AuthProxyService.getSessionStatus(useCookie: true);
      if (status != 200) {
        debugPrint(
          "[Auth] Cookie session check: No active session (status: $status)",
        );
        return;
      }

      if (!shouldPromoteCookieSession(
        currentToken: AuthTokenStore.getToken(),
        loginChallenge: loginChallenge,
      )) {
        return;
      }
      AuthTokenStore.setCookieMode(provider: provider);
      AuthTokenStore.clearPendingProvider();
      if (mounted) {
        await ref.read(profileProvider.notifier).loadProfile();
        await _onCookieLoginSuccess(provider);
      }
    } catch (e) {
      if (!silent) {
        _showError(
          tr(
            'msg.userfront.login.cookie_check_failed',
            params: {'error': e.toString().replaceFirst('Exception: ', '')},
          ),
        );
      }
    }
  }

  Future<void> _onCookieLoginSuccess(String provider) async {
    debugPrint("[Auth] Cookie-based login success. Provider: $provider");
    if (_hasLoginChallenge) {
      final accepted = await _acceptOidcLoginAndRedirect();
      if (accepted) {
        return;
      }
      if (mounted) {
        _showError(tr('msg.userfront.login.oidc_failed'));
      }
      return;
    }

    final token = AuthTokenStore.getToken();
    if (token != null && token.isNotEmpty) {
      final redirectUrl = _redirectUrl;
      if (WebAuthIntegration.isPopup() ||
          (redirectUrl != null && redirectUrl.isNotEmpty)) {
        debugPrint(
          "[Auth] Cookie session with external integration. Notifying...",
        );
        WebAuthIntegration.sendLoginSuccess(token);
        return;
      }
    }

    if (mounted) {
      _goLocalizedHomeOnce();
    }
  }

  void _goLocalizedHomeOnce() {
    if (!mounted || _localNavigationCompleted) {
      return;
    }
    _localNavigationCompleted = true;
    context.go(buildLocalizedHomePath(Uri.base));
  }

  Future<void> _attemptOidcAutoAccept() async {
    if (_oidcAutoAcceptTried) return;
    _oidcAutoAcceptTried = true;
    final loginChallenge = _loginChallenge;
    if (loginChallenge == null || loginChallenge.isEmpty) {
      return;
    }
    if (!loginChallengeLoopGuard.shouldAllowAutoAccept(loginChallenge)) {
      debugPrint(
        "[Auth] OIDC auto-accept blocked by loop guard for login_challenge",
      );
      return;
    }
    loginChallengeLoopGuard.markAutoAcceptAttempt(loginChallenge);

    final token = AuthTokenStore.getToken();
    if (token != null && token.isNotEmpty) {
      final accepted = await _acceptOidcLoginAndRedirect(token: token);
      if (accepted) {
        loginChallengeLoopGuard.clear(loginChallenge);
        return;
      }
    }

    try {
      // 401 응답은 세션이 없는 정상적인 상태이므로 예외로 처리하지 않고 우아하게 중단합니다.
      final status = await AuthProxyService.getSessionStatus(useCookie: true);
      if (status == 200) {
        AuthTokenStore.setCookieMode(
          provider: AuthTokenStore.getProvider() ?? 'ory',
        );
        final accepted = await _acceptOidcLoginAndRedirect();
        if (accepted) {
          loginChallengeLoopGuard.clear(loginChallenge);
          return;
        }
      } else {
        debugPrint(
          "[Auth] OIDC auto-accept: No active session (status: $status)",
        );
      }
    } catch (e) {
      debugPrint("[Auth] OIDC auto-accept cookie check failed: $e");
    }
  }

  Future<bool> _acceptOidcLoginAndRedirect({String? token}) async {
    final loginChallenge = _loginChallenge;
    if (loginChallenge == null || loginChallenge.isEmpty) {
      return false;
    }
    try {
      final res = await AuthProxyService.acceptOidcLogin(
        loginChallenge,
        token: token,
      );

      // IMPORTANT: If backend returned a token during OIDC flow, save it to fix login state.
      final jwt = res['sessionJwt'] ?? res['token'] ?? token;
      if (jwt != null && jwt.isNotEmpty) {
        final provider =
            res['provider'] as String? ?? AuthTokenStore.getProvider();
        await AuthNotifier.instance.onLoginSuccess(jwt, provider: provider);
      }

      final redirectTo = res['redirectTo'] as String?;
      if (redirectTo != null && redirectTo.isNotEmpty) {
        // Give 50ms delay for localStorage to settle
        await Future.delayed(const Duration(milliseconds: 50));
        return _redirectToOidcTarget(redirectTo, source: 'accept_oidc_login');
      }
    } catch (e) {
      debugPrint("[Auth] OIDC login auto-accept failed: $e");
    }
    return false;
  }

  bool _redirectToOidcTarget(String redirectTo, {required String source}) {
    final checked = validateOidcRedirectTarget(redirectTo);
    _logOidcRedirectDiagnostics(source: source, checked: checked);
    debugPrint(
      "[Auth] OIDC redirect check ($source): valid=${checked.isValid}, reason=${checked.reason}, len=${checked.length}, host=${checked.host}, path=${checked.path}, has_login_verifier=${checked.hasLoginVerifier}",
    );

    if (!checked.isValid || checked.uri == null) {
      if (mounted) {
        _showError(tr('msg.userfront.login.oidc_failed'));
      }
      return false;
    }

    try {
      debugPrint(
        "[Auth] OIDC redirect execute ($source): host=${checked.host}, path=${checked.path}, redirect_uri_host=${checked.redirectUriHost}, redirect_uri_port=${checked.redirectUriPort}, state_len=${checked.stateLength}, login_verifier_len=${checked.loginVerifierLength}",
      );
      webWindow.redirectTo(checked.uri.toString());
      return true;
    } catch (e) {
      debugPrint("[Auth] OIDC redirect failed ($source): $e");
      if (mounted) {
        _showError(tr('msg.userfront.login.oidc_failed'));
      }
      return false;
    }
  }

  bool get _hasLoginChallenge {
    final loginChallenge = _loginChallenge;
    return loginChallenge != null && loginChallenge.isNotEmpty;
  }

  LoginChallengeResolution _resolveLoginChallenge(Uri uri) {
    return resolveLoginChallenge(
      widgetLoginChallenge: widget.loginChallenge,
      uri: uri,
      rawSearch: webWindow.currentSearch(),
      rawHref: webWindow.currentHref(),
    );
  }

  void _logLoginChallengeDiagnostics({
    required String phase,
    required LoginChallengeResolution resolution,
  }) {
    final current = Uri.base;
    final currentQueryKeys = current.queryParameters.keys.toList()..sort();
    final payload = <String, Object?>{
      'phase': phase,
      'current_path': current.path,
      'current_query_keys': currentQueryKeys,
      'stored_has_login_challenge': _hasLoginChallenge,
      'stored_login_challenge_len': _loginChallenge?.length ?? 0,
      ...resolution.toDiagnostics(),
    };
    debugPrint("[Auth] login_challenge diagnostics: ${jsonEncode(payload)}");
  }

  void _logOidcRedirectDiagnostics({
    required String source,
    required OidcRedirectCheckResult checked,
  }) {
    final current = Uri.base;
    final currentQueryKeys = current.queryParameters.keys.toList()..sort();

    final payload = <String, Object?>{
      'source': source,
      'current_path': current.path,
      'current_query_param_count': current.queryParameters.length,
      'current_query_keys': currentQueryKeys,
      'has_login_challenge': _hasLoginChallenge,
      'login_challenge_len': _loginChallenge?.length ?? 0,
      ...checked.toDiagnostics(),
    };

    debugPrint("[Auth] OIDC redirect diagnostics: ${jsonEncode(payload)}");
  }

  void _resetLinkLoginState() {
    _linkPendingRef = null;
    _lastLinkLoginId = null;
    _lastLinkIsEmail = true;
    _linkResendTimer?.cancel();
    _linkResendTimer = null;
    _linkResendSeconds = 0;
    _linkExpireTimer?.cancel();
    _linkExpireTimer = null;
    _linkExpireSeconds = 0;
    _linkExpired = false;
    _shortCodePrefixController.clear();
    _shortCodeDigitsController.clear();
  }

  void _dismissOverlays() {
    if (!mounted || _dismissedOverlays) {
      return;
    }
    _dismissedOverlays = true;
    final navigator = Navigator.of(context, rootNavigator: true);
    navigator.popUntil((route) => route is! PopupRoute);
  }

  bool _parseBoolParam(String? value) {
    if (value == null) {
      return false;
    }
    final normalized = value.toLowerCase();
    return normalized == 'true' || normalized == '1' || normalized == 'yes';
  }

  void _startLinkResendTimer(int seconds) {
    _linkResendSeconds = seconds;
    _linkResendTimer?.cancel();
    _linkResendTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (!mounted) return;
      setState(() {
        if (_linkResendSeconds > 0) {
          _linkResendSeconds--;
        } else {
          timer.cancel();
        }
      });
    });
  }

  void _startLinkExpireTimer(int seconds) {
    _linkExpireSeconds = seconds;
    _linkExpireTimer?.cancel();
    _linkExpireTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (!mounted) return;
      if (_linkExpireSeconds > 0) {
        setState(() {
          _linkExpireSeconds--;
        });
        return;
      }
      timer.cancel();
      if (mounted) {
        setState(() {
          _linkExpired = true;
        });
        _showInfo(tr('msg.userfront.login.link_timeout'));
      }
    });
  }

  String _getLoginIdFromJwt(String jwt) {
    try {
      final parts = jwt.split('.');
      if (parts.length != 3) return 'User';

      final payload = utf8.decode(
        base64Url.decode(base64Url.normalize(parts[1])),
      );
      final data = json.decode(payload);
      return data['name'] ?? data['email'] ?? data['sub'] ?? 'User';
    } catch (e) {
      debugPrint("[JWT] Decode error: $e");
      return 'User';
    }
  }

  void _handleTabSelection() {
    if (_tabController.index == 2 && _qrPendingRef == null) {
      _startQrFlow();
    } else if (_tabController.index != 2) {
      _stopQrPolling();
    }
  }

  Future<void> _startQrFlow() async {
    if (_isQrLoading) return;
    setState(() {
      _isQrLoading = true;
      _qrImageBase64 = null;
      _qrRemainingSeconds = 0;
      _qrExpired = false;
    });

    try {
      final res = await AuthProxyService.initQrLogin();
      if (mounted) {
        setState(() {
          _qrImageBase64 = res['qrCode'];
          _qrPendingRef = res['pendingRef'];
          _qrRemainingSeconds = res['expiresIn'] ?? 300;
          final interval = res['interval'];
          if (interval is int && interval > 0) {
            _qrPollIntervalMs = interval * 1000;
          } else {
            _qrPollIntervalMs = 2000;
          }
          _isQrLoading = false;
        });
        _startQrPolling();
        _startCountdown();
      }
    } catch (e) {
      _showError(
        tr(
          'msg.userfront.login.qr_init_failed',
          params: {'error': e.toString()},
        ),
      );
      if (mounted) setState(() => _isQrLoading = false);
    }
  }

  void _startCountdown() {
    _qrCountdownTimer?.cancel();
    _qrCountdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      if (!mounted || _qrRemainingSeconds <= 0) {
        timer.cancel();
        if (_qrRemainingSeconds <= 0) {
          _stopQrPolling();
          if (mounted) {
            setState(() {
              _qrExpired = true;
            });
            _showInfo(tr('msg.userfront.login.qr_expired'));
          }
        }
        return;
      }
      setState(() {
        _qrRemainingSeconds--;
      });
    });
  }

  void _startQrPolling() {
    _qrPollingTimer?.cancel();
    _qrPollingTimer = Timer.periodic(
      Duration(milliseconds: _qrPollIntervalMs),
      (timer) async {
        if (_qrPendingRef == null || !mounted || _qrRemainingSeconds <= 0) {
          timer.cancel();
          return;
        }

        try {
          final pendingRef = _qrPendingRef;
          if (pendingRef == null || pendingRef.isEmpty) {
            return;
          }
          final res = await AuthProxyService.pollQrStatus(pendingRef);
          if (res['error'] == 'slow_down') {
            final interval = res['interval'];
            if (interval is int && interval > 0) {
              final nextIntervalMs = interval * 1000;
              if (nextIntervalMs != _qrPollIntervalMs) {
                _qrPollIntervalMs = nextIntervalMs;
                timer.cancel();
                _startQrPolling();
                return;
              }
            } else {
              _qrPollIntervalMs += 500;
              timer.cancel();
              _startQrPolling();
              return;
            }
          }
          if (res['error'] == 'authorization_pending') {
            return;
          }
          if (res['error'] == 'expired_token') {
            timer.cancel();
            _qrCountdownTimer?.cancel();
            if (mounted) {
              setState(() {
                _qrExpired = true;
              });
            }
            _showError(tr('msg.userfront.login.qr_expired'));
            return;
          }

          if (res['status'] == 'ok') {
            timer.cancel();
            _qrCountdownTimer?.cancel();
            final token =
                res['sessionJwt'] ?? res['sessionToken'] ?? res['token'];
            if (token is String && token.isNotEmpty) {
              _completeLoginFromToken(token);
            } else {
              _showError(tr('msg.userfront.login.token_missing'));
            }
          }
        } catch (e) {
          debugPrint("[QR] Polling error: $e");
        }
      },
    );
  }

  void _stopQrPolling() {
    _qrPollingTimer?.cancel();
    _qrPollingTimer = null;
    _qrCountdownTimer?.cancel();
    _qrCountdownTimer = null;
    _qrPendingRef = null;
  }

  String _formatTime(int seconds) {
    final m = seconds ~/ 60;
    final s = seconds % 60;
    return "${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}";
  }

  void _completeLoginFromToken(
    String token, {
    String? provider,
    bool closeDialog = false,
  }) {
    final isJwt = token.split('.').length == 3;
    if (isJwt) {
      _getLoginIdFromJwt(token);
    }

    if (!mounted) return;
    if (closeDialog && Navigator.canPop(context)) {
      Navigator.of(context).pop();
    }
    _onLoginSuccess(token, provider: provider);
  }

  Future<bool> _hasValidLocalSession() async {
    final token = AuthTokenStore.getToken();
    final usesCookie = AuthTokenStore.usesCookie();
    if (token == null && !usesCookie) {
      return false;
    }

    try {
      final status = await AuthProxyService.getSessionStatus(
        token: token,
        useCookie: usesCookie,
      );
      if (status == 200) {
        return true;
      }
      if (status == 401 || status == 403) {
        AuthTokenStore.clear();
      }
    } catch (e) {
      debugPrint("[Auth] 세션 확인 실패: $e");
    }
    return false;
  }

  bool _moveVerificationOnlyResultToCleanRoute() {
    if (!_verificationOnly || widget.verificationCompleteOnly) {
      return false;
    }
    final localeCode =
        extractLocaleFromPath(Uri.base) ?? resolvePreferredLocaleCode();
    final target = buildLocalizedVerificationCompletePath(localeCode);
    if (mounted) {
      context.go(target);
    } else {
      webWindow.redirectTo(target);
    }
    return true;
  }

  void _markVerificationApproved(
    String messageKey, {
    String? titleKey,
    String? pageTitleKey,
    String? actionLabelKey,
    String actionPath = '/',
    bool autoRedirect = false,
    Duration redirectDelay = const Duration(seconds: 2),
    VoidCallback? onAction,
  }) {
    if (!mounted) return;
    if (_moveVerificationOnlyResultToCleanRoute()) {
      return;
    }
    setState(() {
      _verificationApproved = true;
      _verificationMessageKey = messageKey;
      _verificationTitleKey =
          titleKey ?? 'ui.userfront.login.verification.title';
      _verificationPageTitleKey =
          pageTitleKey ?? 'ui.userfront.login.verification.page_title';
      _verificationActionLabelKey =
          actionLabelKey ?? 'ui.userfront.login.verification.action_label';
      _onVerificationAction = onAction;
    });
    _verificationRedirectTimer?.cancel();
    if (autoRedirect) {
      _verificationRedirectTimer = Timer(redirectDelay, () {
        if (!mounted) return;
        if (onAction != null) {
          onAction();
        } else {
          context.go(actionPath);
        }
      });
    }
  }

  VoidCallback? _onVerificationAction;

  void _runVerificationExitAction() {
    _onVerificationAction?.call();
  }

  void _closeVerificationWindowIfPossible() {
    webWindow.close();
  }

  void _moveToSigninOrCloseVerificationWindow() {
    if (webWindow.hasOpener()) {
      webWindow.close();
      return;
    }
    AuthTokenStore.skipNextCookieSessionCheck();
    context.go(buildLocalizedSigninPath(Uri.base));
  }

  void _handleVerificationResultPrimaryAction() {
    if (_onVerificationAction != null) {
      _runVerificationExitAction();
      return;
    }
    if (_verificationOnly) {
      _closeVerificationWindowIfPossible();
      return;
    }
    final hasLocalSession =
        (AuthTokenStore.getToken()?.isNotEmpty ?? false) ||
        AuthTokenStore.usesCookie();
    final target = hasLocalSession
        ? buildLocalizedHomePath(Uri.base)
        : buildLocalizedSigninPath(Uri.base);
    if (mounted) {
      setState(() {
        _verificationOnly = false;
        _verificationApproved = false;
      });
    }
    context.go(target);
  }

  void _markRemoteVerificationApproved() {
    _markVerificationApproved(
      'msg.userfront.login.verification.approved_remote',
      titleKey: 'ui.userfront.login.verification.title_remote',
      actionLabelKey: 'ui.userfront.login.verification.action_label_remote',
      onAction: _moveToSigninOrCloseVerificationWindow,
    );
  }

  Widget _buildVerificationResultView() {
    final theme = Theme.of(context);
    final colorScheme = theme.colorScheme;
    final accentColor = colorScheme.brightness == Brightness.dark
        ? const Color(0xFF93C5FD)
        : const Color(0xFF1E3A8A);
    final message = tr(
      _verificationMessageKey ?? 'msg.userfront.login.verification.success',
    );
    final verificationTitle = tr(_verificationTitleKey);
    final closeHint = tr('msg.userfront.login.verification.close_hint');
    final showCloseHint =
        _verificationActionLabelKey ==
        'ui.userfront.login.verification.action_label_close';

    return SafeArea(
      child: SingleChildScrollView(
        padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
        child: Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: 468),
            child: LayoutBuilder(
              builder: (context, constraints) {
                final isCompact = constraints.maxWidth < 360;
                final iconBoxSize = isCompact ? 76.0 : 88.0;
                final iconSize = isCompact ? 48.0 : 56.0;
                final verticalGap = isCompact ? 16.0 : 20.0;
                final controlsOffset = isCompact ? 150.0 : 170.0;
                final cardRadius = isCompact ? 24.0 : 28.0;
                final cardPadding = isCompact
                    ? const EdgeInsets.fromLTRB(20, 24, 20, 22)
                    : const EdgeInsets.fromLTRB(30, 34, 30, 28);

                return Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    SizedBox(height: controlsOffset),
                    DecoratedBox(
                      decoration: BoxDecoration(
                        color: colorScheme.surface,
                        borderRadius: BorderRadius.circular(cardRadius),
                        border: Border.all(
                          color: colorScheme.outlineVariant.withValues(
                            alpha: 0.7,
                          ),
                        ),
                        boxShadow: [
                          BoxShadow(
                            color: colorScheme.shadow.withValues(alpha: 0.08),
                            blurRadius: 28,
                            offset: const Offset(0, 16),
                          ),
                        ],
                      ),
                      child: Padding(
                        padding: cardPadding,
                        child: Column(
                          mainAxisSize: MainAxisSize.min,
                          children: [
                            Container(
                              width: iconBoxSize,
                              height: iconBoxSize,
                              decoration: BoxDecoration(
                                shape: BoxShape.circle,
                                gradient: LinearGradient(
                                  colors: [
                                    colorScheme.primary.withValues(alpha: 0.18),
                                    colorScheme.tertiary.withValues(
                                      alpha: 0.14,
                                    ),
                                  ],
                                  begin: Alignment.topLeft,
                                  end: Alignment.bottomRight,
                                ),
                              ),
                              alignment: Alignment.center,
                              child: Icon(
                                Icons.person,
                                size: iconSize,
                                color: colorScheme.primary,
                              ),
                            ),
                            SizedBox(height: verticalGap),
                            Text(
                              verificationTitle,
                              textAlign: TextAlign.center,
                              softWrap: true,
                              style: TextStyle(
                                fontSize: isCompact ? 22 : 26,
                                fontWeight: FontWeight.w800,
                                color: accentColor,
                                letterSpacing: -0.4,
                                height: 1.25,
                              ),
                            ),
                            const SizedBox(height: 12),
                            Text(
                              message,
                              textAlign: TextAlign.center,
                              softWrap: true,
                              style:
                                  (isCompact
                                          ? theme.textTheme.bodyMedium
                                          : theme.textTheme.bodyLarge)
                                      ?.copyWith(
                                        height: 1.6,
                                        color: colorScheme.onSurfaceVariant,
                                      ),
                            ),
                            const SizedBox(height: 24),
                            Center(
                              child: ConstrainedBox(
                                constraints: const BoxConstraints(
                                  minWidth: 180,
                                  maxWidth: 320,
                                ),
                                child: SizedBox(
                                  width: double.infinity,
                                  child: FilledButton(
                                    onPressed:
                                        _handleVerificationResultPrimaryAction,
                                    child: Text(
                                      tr(_verificationActionLabelKey),
                                      textAlign: TextAlign.center,
                                    ),
                                  ),
                                ),
                              ),
                            ),
                            if (showCloseHint) ...[
                              const SizedBox(height: 10),
                              Text(
                                closeHint,
                                textAlign: TextAlign.center,
                                softWrap: true,
                                style: theme.textTheme.bodyMedium?.copyWith(
                                  height: 1.5,
                                  color: colorScheme.onSurfaceVariant,
                                ),
                              ),
                            ],
                          ],
                        ),
                      ),
                    ),
                    const SizedBox(height: 18),
                    const Wrap(
                      alignment: WrapAlignment.center,
                      spacing: 10,
                      runSpacing: 10,
                      children: [ThemeToggleButton(), LanguageSelector()],
                    ),
                  ],
                );
              },
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildVerificationPendingView() {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(24.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const SizedBox(
              width: 48,
              height: 48,
              child: CircularProgressIndicator(strokeWidth: 4),
            ),
            const SizedBox(height: 20),
            Text(
              tr('ui.userfront.login.verification.title_pending'),
              textAlign: TextAlign.center,
              style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 12),
            Text(
              tr('msg.userfront.login.verification.pending_remote'),
              textAlign: TextAlign.center,
              style: const TextStyle(color: Colors.black54),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildVerificationOnlyScaffold() {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        title: Text(tr(_verificationPageTitleKey)),
        leading: _verificationApproved && _onVerificationAction != null
            ? IconButton(
                icon: const Icon(Icons.close),
                onPressed: _runVerificationExitAction,
              )
            : null,
        actions: const [ThemeToggleButton(compact: true)],
      ),
      body: _verificationApproved
          ? _buildVerificationResultView()
          : _buildVerificationPendingView(),
    );
  }

  Future<void> _verifyToken(String token) async {
    debugPrint("[Auth] Starting verification for token: $token");
    try {
      // Use Backend to verify the token (Backend-Driven Flow)
      final res = await AuthProxyService.verifyMagicLink(
        token,
        verifyOnly: _verificationOnly,
      );
      debugPrint("[Auth] Verification successful for token: $token");
      final jwt = res['token'] ?? res['sessionJwt'] ?? res['sessionToken'];
      final status = res['status']?.toString();
      final hasLocalSession = await _hasValidLocalSession();
      final actionPath = hasLocalSession
          ? buildLocalizedHomePath(Uri.base)
          : buildLocalizedSigninPath(Uri.base);

      if (status == 'approved' || (jwt == null && _verificationOnly)) {
        if (mounted) {
          _markRemoteVerificationApproved();
        }
        return;
      }

      if (jwt is String && jwt.isNotEmpty) {
        if (_verificationOnly) {
          _markRemoteVerificationApproved();
          return;
        }
        if (hasLocalSession) {
          _markVerificationApproved(
            'msg.userfront.login.verification.approved_local',
            actionPath: actionPath,
          );
          return;
        }
        _onLoginSuccess(jwt, provider: res['provider'] as String?);
        return;
      }

      if (mounted) {
        _markVerificationApproved(
          'msg.userfront.login.verification.approved',
          actionPath: actionPath,
        );
      }
    } catch (e) {
      debugPrint("[Auth] Verification FAILED for token: $token. Error: $e");

      // Handle the case where the token is already verified/used (common in remote flows)
      final errorStr = e.toString();
      if (errorStr.contains('already_used') ||
          errorStr.contains('already_verified') ||
          errorStr.contains('session_active')) {
        if (mounted) {
          _markRemoteVerificationApproved();
        }
        return;
      }

      if (mounted) {
        _showError(
          tr(
            'msg.userfront.login.verification_failed',
            params: {'error': e.toString()},
          ),
        );
      }
    }
  }

  Future<void> _verifyLoginCode(
    String loginId,
    String code, {
    String? pendingRef,
  }) async {
    final sanitizedLoginId = loginId.replaceAll(' ', '+');
    debugPrint(
      "[Auth] Starting code verification for loginId: $sanitizedLoginId",
    );
    try {
      final res = await AuthProxyService.verifyLoginCode(
        sanitizedLoginId,
        code,
        pendingRef: pendingRef,
        verifyOnly: _verificationOnly,
      );
      final jwt = res['sessionJwt'] ?? res['sessionToken'] ?? res['token'];
      final status = res['status']?.toString();
      debugPrint(
        "[Auth] Code verification successful for loginId: $sanitizedLoginId",
      );
      final hasLocalSession = await _hasValidLocalSession();
      final actionPath = hasLocalSession
          ? buildLocalizedHomePath(Uri.base)
          : buildLocalizedSigninPath(Uri.base);

      if (jwt == null && status == 'approved') {
        if (mounted) {
          _markRemoteVerificationApproved();
        }
        return;
      }

      if (jwt is String && jwt.isNotEmpty) {
        if (hasLocalSession) {
          _markVerificationApproved(
            'msg.userfront.login.verification.approved_local',
            actionPath: actionPath,
          );
          return;
        }
        if (_verificationOnly) {
          _markRemoteVerificationApproved();
          return;
        }
        _onLoginSuccess(jwt, provider: res['provider'] as String?);
        return;
      }

      if (_verificationOnly && mounted) {
        _markRemoteVerificationApproved();
      }
    } catch (e) {
      debugPrint(
        "[Auth] Code verification FAILED for loginId: $sanitizedLoginId. Error: $e",
      );

      // Handle the case where the code is already verified/used (common in remote flows)
      final errorStr = e.toString();
      if (errorStr.contains('already_used') ||
          errorStr.contains('already_verified') ||
          errorStr.contains('session_active')) {
        if (mounted) {
          _markRemoteVerificationApproved();
        }
        return;
      }

      if (mounted) {
        _showError(
          tr(
            'msg.userfront.login.verification_failed',
            params: {'error': e.toString()},
          ),
        );
      }
    }
  }

  Future<void> _verifyShortCode(String shortCode) async {
    final sanitized = shortCode.trim().toUpperCase();
    if (sanitized.isEmpty) return;
    debugPrint("[Auth] Starting short code verification for code: $sanitized");
    try {
      final res = await AuthProxyService.verifyLoginShortCode(
        sanitized,
        verifyOnly: _verificationOnly,
      );
      final jwt = res['sessionJwt'] ?? res['sessionToken'] ?? res['token'];
      final status = res['status']?.toString();
      debugPrint("[Auth] Short code verification successful");
      final hasLocalSession = await _hasValidLocalSession();
      final actionPath = hasLocalSession
          ? buildLocalizedHomePath(Uri.base)
          : buildLocalizedSigninPath(Uri.base);

      if (jwt == null && status == 'approved') {
        if (mounted) {
          _markRemoteVerificationApproved();
        }
        return;
      }

      if (jwt is String && jwt.isNotEmpty) {
        if (hasLocalSession) {
          _markVerificationApproved(
            'msg.userfront.login.verification.approved_local',
            actionPath: actionPath,
          );
          return;
        }
        if (_verificationOnly) {
          _markRemoteVerificationApproved();
          return;
        }
        _onLoginSuccess(jwt, provider: res['provider'] as String?);
        return;
      }

      if (_verificationOnly && mounted) {
        _markRemoteVerificationApproved();
      }
    } catch (e) {
      debugPrint("[Auth] Short code verification FAILED. Error: $e");

      // Handle the case where the code is already verified/used (common in remote flows)
      final errorStr = e.toString();
      if (errorStr.contains('already_used') ||
          errorStr.contains('already_verified') ||
          errorStr.contains('session_active')) {
        if (mounted) {
          _markRemoteVerificationApproved();
        }
        return;
      }

      if (mounted) {
        _showError(
          tr(
            'msg.userfront.login.verification_failed',
            params: {'error': e.toString()},
          ),
        );
      }
    }
  }

  @override
  void dispose() {
    _stopQrPolling();
    _verificationRedirectTimer?.cancel();
    _tabController.dispose();
    _linkIdController.dispose();
    _passwordLoginIdController.dispose();
    _passwordController.dispose();
    _passwordFocusNode
      ..removeListener(_handlePasswordFocusChange)
      ..dispose();
    HardwareKeyboard.instance.removeHandler(_handleHardwareKeyEvent);
    _shortCodePrefixController.dispose();
    _shortCodeDigitsController.dispose();
    _linkResendTimer?.cancel();
    super.dispose();
  }

  Future<void> _handlePasswordLogin() async {
    final input = _passwordLoginIdController.text.trim();
    final password = _passwordController.text.trim();
    if (input.isEmpty || password.isEmpty) {
      _showError(tr('msg.userfront.login.password.missing_credentials'));
      return;
    }

    String loginId = input;
    if (!input.contains('@')) {
      loginId = input.replaceAll(RegExp(r'[-\s]'), '');
      if (loginId.startsWith('010')) {
        loginId = '+82${loginId.substring(1)}';
      }
    }

    try {
      final res = await AuthProxyService.loginWithPassword(
        loginId,
        password,
        loginChallenge: _loginChallenge,
      );

      final jwt = res['sessionJwt'] ?? res['sessionToken'] ?? res['token'];
      final provider = res['provider'] as String?;
      final redirectTo = res['redirectTo'] as String?;

      if (jwt != null) {
        _onLoginSuccess(jwt, provider: provider, redirectTo: redirectTo);
      } else if (redirectTo != null && redirectTo.isNotEmpty) {
        webWindow.redirectTo(redirectTo);
      } else {}
    } catch (e) {
      final errorMessage = e.toString().replaceFirst('Exception: ', '');
      try {
        await AuthProxyService.logError(
          '[PasswordLogin] $errorMessage',
          error: e,
        );
      } catch (_) {
        // Ignore client-log relay failures and continue with user feedback.
      }
      if (e.toString().contains("User not registered")) {
        _showUnregisteredDialog();
      } else {
        _showError(
          tr(
            'msg.userfront.login.password.failed',
            params: {'error': errorMessage},
          ),
        );
      }
    }
  }

  Future<void> _handleLinkLogin() async {
    final input = _linkIdController.text.trim();
    if (input.isEmpty) return;

    String loginId = input;
    if (!input.contains('@')) {
      loginId = input.replaceAll(RegExp(r'[-\s]'), '');
      if (loginId.startsWith('010')) {
        loginId = '+82${loginId.substring(1)}';
      }
    }

    debugPrint("[Auth] Initiating Enchanted Link for: $loginId");

    try {
      await _startEnchantedFlow(loginId, isEmail: input.contains('@'));
    } catch (e) {
      if (e.toString().contains("User not registered")) {
        _showUnregisteredDialog();
      } else {
        _showError(
          tr(
            'msg.userfront.login.link_failed',
            params: {'error': e.toString()},
          ),
        );
      }
    }
  }

  Future<void> _startEnchantedFlow(
    String loginId, {
    required bool isEmail,
    bool codeOnly = false,
  }) async {
    try {
      final initResponse = await AuthProxyService.initEnchantedLink(
        loginId,
        codeOnly: codeOnly,
        drySend: _drySendEnabled,
      );
      final pendingRef = initResponse['pendingRef'];
      final mode = (initResponse['mode'] ?? '').toString();
      final provider = (initResponse['provider'] ?? '').toString();
      final interval = initResponse['interval'];
      final resendAfter = initResponse['resendAfter'];
      final expiresIn = initResponse['expiresIn'];
      debugPrint(
        "[Auth] Link Sent. PendingRef: $pendingRef, Mode: $mode, Provider: $provider",
      );

      if (mounted) {
        setState(() {
          _linkPendingRef = pendingRef?.toString();
          _lastLinkLoginId = loginId;
          _lastLinkIsEmail = isEmail;
          _linkExpired = false;
        });
        _dismissOverlays();
        _showInfo(
          isEmail
              ? tr('msg.userfront.login.link_sent_email')
              : tr('msg.userfront.login.link_sent_phone'),
        );

        final initialInterval = (interval is int && interval > 0)
            ? Duration(seconds: interval)
            : const Duration(seconds: 2);
        if (resendAfter is int && resendAfter > 0) {
          _startLinkResendTimer(resendAfter);
        }
        if (expiresIn is int && expiresIn > 0) {
          _startLinkExpireTimer(expiresIn);
        }
        _pollForSession(pendingRef, initialInterval: initialInterval);
      }
    } catch (e) {
      debugPrint("[Auth] Initialization failed: $e");
      if (mounted) {
        setState(_resetLinkLoginState);
      }
      if (e.toString().contains("User not registered")) {
        _showUnregisteredDialog();
      } else {
        _showError(
          tr(
            'msg.userfront.login.link_send_failed',
            params: {'error': e.toString()},
          ),
        );
      }
    }
  }

  Future<void> _pollForSession(
    String pendingRef, {
    Duration? initialInterval,
  }) async {
    int attempts = 0;
    const maxAttempts = 60;
    var pollInterval = initialInterval ?? const Duration(seconds: 2);
    debugPrint("[Auth] Starting poll for ref: $pendingRef");

    while (attempts < maxAttempts && mounted) {
      if (_linkPendingRef != pendingRef) {
        return;
      }
      await Future.delayed(pollInterval);
      attempts++;

      try {
        final result = await AuthProxyService.pollEnchantedLink(pendingRef);

        if (result['error'] == 'slow_down') {
          final interval = result['interval'];
          if (interval is int && interval > 0) {
            pollInterval = Duration(seconds: interval);
          } else {
            pollInterval += const Duration(seconds: 1);
          }
          continue;
        }
        if (result['error'] == 'authorization_pending') {
          continue;
        }
        if (result['error'] == 'expired_token') {
          if (mounted) {
            Navigator.of(context).pop();
            _showError(tr('msg.userfront.login.link_timeout'));
          }
          return;
        }

        if (result['status'] == 'ok') {
          final token =
              result['sessionJwt'] ?? result['sessionToken'] ?? result['token'];
          if (token is String && token.isNotEmpty) {
            debugPrint("[Auth] Polling SUCCESS. Token received.");
            _completeLoginFromToken(
              token,
              provider: result['provider'] as String?,
              closeDialog: true,
            );
            return;
          }
          debugPrint("[Auth] Polling SUCCESS but token missing.");
          if (mounted && Navigator.canPop(context)) {
            Navigator.of(context).pop();
          }
          _showError(tr('msg.userfront.login.token_missing'));
          return;
        }
      } catch (e) {
        debugPrint("[Auth] Polling error (attempt $attempts): $e");
      }
    }

    if (mounted) {
      debugPrint("[Auth] Polling timed out for ref: $pendingRef");
      Navigator.of(context).pop();
      _showError(tr('msg.userfront.login.link_timeout'));
    }
  }

  void _showError(String message) {
    if (!mounted) return;
    ToastService.error(message);
    try {
      AuthProxyService.logError(message);
    } catch (e) {
      // ignore
    }
  }

  void _showInfo(String message) {
    if (!mounted) return;
    ToastService.success(message);
  }

  void _logTokenDetails(String jwt) {
    try {
      final parts = jwt.split('.');
      if (parts.length != 3) return;

      final decodedPayload = base64Url.decode(base64Url.normalize(parts[1]));
      final payloadJson = utf8.decode(decodedPayload);
      final data = json.decode(payloadJson) as Map<String, dynamic>;

      final accessExpValue = data['exp'] as num?;
      final accessExp = accessExpValue != null
          ? DateTime.fromMillisecondsSinceEpoch(accessExpValue.toInt() * 1000)
          : 'N/A';
      final refreshExp = data['rexp'] ?? 'N/A';

      debugPrint("""
      [Auth] Session Token Details ---
        - Access Token Expires: $accessExp
        - Refresh Token Expires: $refreshExp
      """);
    } catch (e) {
      debugPrint("[Auth] Failed to decode or log token details: $e");
    }
  }

  Future<void> _onLoginSuccess(
    String token, {
    String? provider,
    String? redirectTo,
  }) async {
    try {
      if (!mounted) {
        return;
      }

      // [Priority 1] Immediate External Redirection
      if (redirectTo != null && redirectTo.isNotEmpty) {
        try {
          final providerName = provider ?? AuthTokenStore.getProvider();
          AuthTokenStore.setToken(token, provider: providerName);
        } catch (stErr) {
          // ignore
        }

        webWindow.redirectTo(redirectTo); // Removed await as it's void
        return;
      }

      // [Priority 2] OIDC Challenge Handling
      final loginChallenge = _loginChallenge;
      if (loginChallenge != null && loginChallenge.isNotEmpty) {
        try {
          // Save token first, it's needed for acceptance
          final providerName = provider ?? AuthTokenStore.getProvider();
          AuthTokenStore.setToken(token, provider: providerName);

          final res = await AuthProxyService.acceptOidcLogin(
            loginChallenge,
            token: token,
          );

          // IMPORTANT: If backend returned a token during OIDC flow, save it to fix login state.
          final jwt = res['sessionJwt'] ?? res['token'] ?? token;
          if (jwt != null && jwt.isNotEmpty) {
            await AuthNotifier.instance.onLoginSuccess(
              jwt,
              provider: res['provider'] as String? ?? providerName,
            );
          }

          final nextRedirectTo = res['redirectTo'] as String?;

          if (nextRedirectTo != null && nextRedirectTo.isNotEmpty) {
            loginChallengeLoopGuard.clear(loginChallenge);
            // Give 50ms delay for localStorage to settle
            await Future.delayed(const Duration(milliseconds: 50));
            webWindow.redirectTo(nextRedirectTo); // Removed await
            return;
          } else {}
        } catch (e) {
          if (e is AuthProxyException &&
              shouldRouteTenantAccessErrorToErrorScreen(e)) {
            final target = buildTenantAccessErrorPath(e, Uri.base);
            if (mounted) {
              context.go(target);
            } else {
              webWindow.redirectTo(target);
            }
            return;
          }
          _showError(tr('msg.userfront.login.oidc_failed'));
          return;
        }
      }

      _logTokenDetails(token);

      final providerName = provider ?? AuthTokenStore.getProvider();

      AuthTokenStore.setToken(token, provider: providerName);
      AuthTokenStore.clearPendingProvider();
      _dismissOverlays();

      try {
        await ref.read(profileProvider.notifier).loadProfile();
      } catch (e) {
        // ignore
      }

      final uri = Uri.base;
      final redirectParam =
          uri.queryParameters['redirect_uri'] ??
          uri.queryParameters['redirect_url'];
      final hasRedirectParam =
          redirectParam != null && redirectParam.isNotEmpty;

      if (WebAuthIntegration.isPopup() || hasRedirectParam) {
        WebAuthIntegration.sendLoginSuccess(token);
        AuthNotifier.instance.notify();
        return;
      }

      if (mounted) {
        _goLocalizedHomeOnce();
      }
    } catch (globalErr) {
      // ignore
    }
  }

  void _showUnregisteredDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(tr('ui.userfront.login.unregistered.title')),
        content: Text(tr('msg.userfront.login.unregistered.body')),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text(tr('ui.common.cancel')),
          ),
          FilledButton(
            onPressed: () {
              Navigator.pop(context);
              _resetLinkLoginState();
              context.push('/signup');
            },
            child: Text(tr('ui.userfront.login.unregistered.action')),
          ),
        ],
      ),
    );
  }

  String _capsLockWarningText(BuildContext context) {
    const key = 'msg.userfront.login.password.caps_lock_on';
    final languageCode = Localizations.localeOf(context).languageCode;
    if (languageCode == 'ko') {
      final translated = tr(key);
      if (translated != key) {
        return translated;
      }
      return 'Caps Lock이 켜져 있습니다.';
    }

    final translated = tr(key, fallback: 'Caps Lock is on.');
    if (translated != key) {
      return translated;
    }
    return 'Caps Lock is on.';
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final colorScheme = theme.colorScheme;
    final mutedColor = colorScheme.onSurfaceVariant;
    final inputForegroundColor = colorScheme.brightness == Brightness.dark
        ? const Color(0xFFE2E8F0)
        : const Color(0xFF334155);
    final primaryColor = colorScheme.brightness == Brightness.dark
        ? const Color(0xFF93C5FD)
        : const Color(0xFF1E3A8A);
    final onPrimaryColor = colorScheme.brightness == Brightness.dark
        ? const Color(0xFF0F172A)
        : Colors.white;
    final inputDecorationTheme = theme.inputDecorationTheme.copyWith(
      filled: false,
      fillColor: Colors.transparent,
      contentPadding: const EdgeInsets.symmetric(horizontal: 18, vertical: 18),
      isDense: true,
      border: OutlineInputBorder(
        borderRadius: BorderRadius.circular(12),
        borderSide: BorderSide(color: colorScheme.outline),
      ),
      enabledBorder: OutlineInputBorder(
        borderRadius: BorderRadius.circular(12),
        borderSide: BorderSide(color: colorScheme.outline),
      ),
      focusedBorder: OutlineInputBorder(
        borderRadius: BorderRadius.circular(12),
        borderSide: BorderSide(color: primaryColor, width: 1.6),
      ),
      labelStyle: TextStyle(color: inputForegroundColor),
      floatingLabelStyle: TextStyle(color: primaryColor),
      hintStyle: TextStyle(color: inputForegroundColor),
      prefixIconColor: inputForegroundColor,
    );
    final localTheme = theme.copyWith(
      inputDecorationTheme: inputDecorationTheme,
      tabBarTheme: theme.tabBarTheme.copyWith(
        dividerColor: colorScheme.outlineVariant,
        indicatorColor: primaryColor,
        labelColor: colorScheme.onSurface,
        unselectedLabelColor: mutedColor,
        labelStyle: theme.textTheme.titleSmall?.copyWith(
          fontWeight: FontWeight.w700,
        ),
        unselectedLabelStyle: theme.textTheme.titleSmall?.copyWith(
          fontWeight: FontWeight.w600,
        ),
      ),
      filledButtonTheme: FilledButtonThemeData(
        style: FilledButton.styleFrom(
          minimumSize: const Size.fromHeight(48),
          backgroundColor: primaryColor,
          foregroundColor: onPrimaryColor,
          textStyle: theme.textTheme.titleSmall?.copyWith(
            fontWeight: FontWeight.w700,
          ),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
          ),
        ),
      ),
      textButtonTheme: TextButtonThemeData(
        style: TextButton.styleFrom(
          foregroundColor: primaryColor,
          textStyle: theme.textTheme.titleSmall?.copyWith(
            fontWeight: FontWeight.w600,
          ),
        ),
      ),
    );

    if (_verificationOnly) {
      return _buildVerificationOnlyScaffold();
    }

    return Scaffold(
      backgroundColor: colorScheme.surfaceContainerLowest,
      body: LayoutBuilder(
        builder: (context, constraints) {
          return Theme(
            data: localTheme,
            child: SingleChildScrollView(
              child: ConstrainedBox(
                constraints: BoxConstraints(minHeight: constraints.maxHeight),
                child: Center(
                  child: Container(
                    constraints: const BoxConstraints(maxWidth: 480),
                    padding: const EdgeInsets.symmetric(
                      horizontal: 28,
                      vertical: 40,
                    ),
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [
                        Text(
                          tr('ui.userfront.app_title'),
                          style: theme.textTheme.headlineMedium?.copyWith(
                            fontSize: 34,
                            fontWeight: FontWeight.w800,
                            letterSpacing: 0,
                          ),
                          textAlign: TextAlign.center,
                        ),
                        if (_drySendEnabled) ...[
                          const SizedBox(height: 20),
                          Container(
                            padding: const EdgeInsets.symmetric(
                              horizontal: 14,
                              vertical: 12,
                            ),
                            decoration: BoxDecoration(
                              color: const Color(0xFFFFF3CD),
                              borderRadius: BorderRadius.circular(16),
                              border: Border.all(
                                color: const Color(0xFFFFC107),
                              ),
                            ),
                            child: Row(
                              children: [
                                const Icon(
                                  Icons.warning_amber_rounded,
                                  color: Color(0xFF8A6D3B),
                                ),
                                const SizedBox(width: 10),
                                Expanded(
                                  child: Text(
                                    tr('msg.userfront.login.dry_send'),
                                    style: const TextStyle(
                                      color: Color(0xFF8A6D3B),
                                      fontSize: 12,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ],
                        const SizedBox(height: 52),
                        Padding(
                          padding: const EdgeInsets.symmetric(horizontal: 34),
                          child: TabBar(
                            controller: _tabController,
                            indicatorSize: TabBarIndicatorSize.label,
                            tabs: [
                              Tab(text: tr('ui.userfront.login.tabs.password')),
                              Tab(text: tr('ui.userfront.login.tabs.link')),
                              Tab(text: tr('ui.userfront.login.tabs.qr')),
                            ],
                          ),
                        ),
                        const SizedBox(height: 28),
                        SizedBox(
                          height: 360,
                          child: TabBarView(
                            controller: _tabController,
                            children: [
                              Padding(
                                padding: const EdgeInsets.only(top: 20),
                                child: Align(
                                  alignment: Alignment.topCenter,
                                  child: ConstrainedBox(
                                    constraints: const BoxConstraints(
                                      maxWidth: 356,
                                    ),
                                    child: Column(
                                      children: [
                                        TextField(
                                          key: const ValueKey(
                                            'password_login_id_input',
                                          ),
                                          controller:
                                              _passwordLoginIdController,
                                          decoration: InputDecoration(
                                            labelText:
                                                _loginIdLabel ??
                                                tr(
                                                  'ui.userfront.login.field.login_id',
                                                ),
                                            prefixIcon: const Icon(
                                              Icons.person_outline,
                                              size: 22,
                                            ),
                                          ),
                                          onSubmitted: (_) =>
                                              _handlePasswordLogin(),
                                        ),
                                        const SizedBox(height: 18),
                                        TextField(
                                          key: const ValueKey(
                                            'password_login_password_input',
                                          ),
                                          focusNode: _passwordFocusNode,
                                          controller: _passwordController,
                                          obscureText: true,
                                          decoration: InputDecoration(
                                            labelText: tr(
                                              'ui.userfront.login.field.password',
                                            ),
                                            prefixIcon: const Icon(
                                              Icons.lock_outline,
                                              size: 22,
                                            ),
                                          ),
                                          onSubmitted: (_) =>
                                              _handlePasswordLogin(),
                                        ),
                                        if (_isPasswordCapsLockOn) ...[
                                          const SizedBox(height: 10),
                                          Row(
                                            children: [
                                              const Icon(
                                                Icons.keyboard_capslock_rounded,
                                                size: 18,
                                                color: Colors.orange,
                                              ),
                                              const SizedBox(width: 8),
                                              Expanded(
                                                child: Text(
                                                  _capsLockWarningText(context),
                                                  style: const TextStyle(
                                                    color: Colors.orange,
                                                    fontSize: 12,
                                                    fontWeight: FontWeight.w600,
                                                  ),
                                                ),
                                              ),
                                            ],
                                          ),
                                        ],
                                        const SizedBox(height: 28),
                                        FilledButton(
                                          key: const ValueKey(
                                            'password_login_submit_button',
                                          ),
                                          onPressed: _handlePasswordLogin,
                                          child: Text(
                                            tr(
                                              'ui.userfront.login.action.submit',
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                ),
                              ),
                              Padding(
                                padding: const EdgeInsets.only(top: 20),
                                child: Align(
                                  alignment: Alignment.topCenter,
                                  child: ConstrainedBox(
                                    constraints: const BoxConstraints(
                                      maxWidth: 356,
                                    ),
                                    child: Column(
                                      children: [
                                        if (_linkPendingRef == null) ...[
                                          TextField(
                                            controller: _linkIdController,
                                            decoration: InputDecoration(
                                              labelText: tr(
                                                'ui.userfront.login.field.login_id',
                                              ),
                                              hintText: '',
                                              prefixIcon: const Icon(
                                                Icons.person_outline,
                                                size: 22,
                                              ),
                                            ),
                                            onSubmitted: (_) =>
                                                _handleLinkLogin(),
                                          ),
                                          const SizedBox(height: 28),
                                          FilledButton(
                                            onPressed: _handleLinkLogin,
                                            child: Text(
                                              tr(
                                                'ui.userfront.login.link.send',
                                              ),
                                            ),
                                          ),
                                          const SizedBox(height: 24),
                                          Text(
                                            tr(
                                              'msg.userfront.login.link.helper',
                                            ),
                                            style: TextStyle(
                                              color: mutedColor,
                                              fontSize: 12,
                                              height: 1.5,
                                            ),
                                            textAlign: TextAlign.center,
                                          ),
                                        ],
                                        if (_linkPendingRef != null) ...[
                                          if (_linkExpired) ...[
                                            Text(
                                              tr(
                                                'msg.userfront.login.link_timeout',
                                              ),
                                              textAlign: TextAlign.center,
                                              style: TextStyle(
                                                color: mutedColor,
                                                fontSize: 12,
                                              ),
                                            ),
                                            const SizedBox(height: 14),
                                            FilledButton(
                                              onPressed: () {
                                                setState(_resetLinkLoginState);
                                              },
                                              child: Text(
                                                tr('ui.common.refresh'),
                                              ),
                                            ),
                                          ] else ...[
                                            Text(
                                              tr(
                                                'msg.userfront.login.link.short_code_help',
                                              ),
                                              style: TextStyle(
                                                color: mutedColor,
                                                fontSize: 12,
                                                height: 1.5,
                                              ),
                                              textAlign: TextAlign.center,
                                            ),
                                            const SizedBox(height: 14),
                                            Row(
                                              children: [
                                                Expanded(
                                                  flex: 2,
                                                  child: TextField(
                                                    controller:
                                                        _shortCodePrefixController,
                                                    textCapitalization:
                                                        TextCapitalization
                                                            .characters,
                                                    decoration: InputDecoration(
                                                      labelText: tr(
                                                        'ui.userfront.login.short_code.prefix',
                                                      ),
                                                      hintText: 'AB',
                                                      hintStyle: TextStyle(
                                                        color: mutedColor,
                                                      ),
                                                      counterText: '',
                                                    ),
                                                    maxLength: 2,
                                                  ),
                                                ),
                                                const SizedBox(width: 10),
                                                Expanded(
                                                  flex: 4,
                                                  child: TextField(
                                                    controller:
                                                        _shortCodeDigitsController,
                                                    keyboardType:
                                                        TextInputType.number,
                                                    decoration: InputDecoration(
                                                      labelText: tr(
                                                        'ui.userfront.login.short_code.digits',
                                                      ),
                                                      hintText: '345678',
                                                      hintStyle: TextStyle(
                                                        color: mutedColor,
                                                      ),
                                                      counterText: '',
                                                      suffixText:
                                                          _linkExpireSeconds > 0
                                                          ? tr(
                                                              'ui.userfront.login.short_code.expire_time',
                                                              params: {
                                                                'time': _formatTime(
                                                                  _linkExpireSeconds,
                                                                ),
                                                              },
                                                            )
                                                          : null,
                                                    ),
                                                    maxLength: 6,
                                                  ),
                                                ),
                                              ],
                                            ),
                                            const SizedBox(height: 14),
                                            FilledButton(
                                              onPressed: () {
                                                final prefix =
                                                    _shortCodePrefixController
                                                        .text
                                                        .trim()
                                                        .toUpperCase();
                                                final digits =
                                                    _shortCodeDigitsController
                                                        .text
                                                        .trim();
                                                if (prefix.length != 2 ||
                                                    digits.length != 6) {
                                                  _showError(
                                                    tr(
                                                      'msg.userfront.login.short_code.invalid',
                                                    ),
                                                  );
                                                  return;
                                                }
                                                _verifyShortCode(
                                                  prefix + digits,
                                                );
                                              },
                                              child: Text(
                                                tr(
                                                  'ui.userfront.login.short_code.submit',
                                                ),
                                              ),
                                            ),
                                            const SizedBox(height: 14),
                                            TextButton(
                                              onPressed: () {
                                                if (_linkResendSeconds > 0) {
                                                  _showInfo(
                                                    tr(
                                                      'msg.userfront.login.link.resend_wait',
                                                      params: {
                                                        'time': _formatTime(
                                                          _linkResendSeconds,
                                                        ),
                                                      },
                                                    ),
                                                  );
                                                  return;
                                                }
                                                final loginId =
                                                    _lastLinkLoginId ??
                                                    _linkIdController.text
                                                        .trim();
                                                if (loginId.isEmpty) {
                                                  _showError(
                                                    tr(
                                                      'msg.userfront.login.link.missing_login_id',
                                                    ),
                                                  );
                                                  return;
                                                }
                                                _startEnchantedFlow(
                                                  loginId,
                                                  isEmail:
                                                      _lastLinkIsEmail ||
                                                      loginId.contains('@'),
                                                  codeOnly: false,
                                                );
                                              },
                                              child: Text(
                                                _linkResendSeconds > 0
                                                    ? tr(
                                                        'ui.userfront.login.link.resend_with_time',
                                                        params: {
                                                          'time': _formatTime(
                                                            _linkResendSeconds,
                                                          ),
                                                        },
                                                      )
                                                    : tr('ui.common.resend'),
                                              ),
                                            ),
                                            if (!_lastLinkIsEmail) ...[
                                              const SizedBox(height: 4),
                                              TextButton(
                                                onPressed: () {
                                                  if (_linkResendSeconds > 0) {
                                                    _showInfo(
                                                      tr(
                                                        'msg.userfront.login.link.resend_wait',
                                                        params: {
                                                          'time': _formatTime(
                                                            _linkResendSeconds,
                                                          ),
                                                        },
                                                      ),
                                                    );
                                                    return;
                                                  }
                                                  final loginId =
                                                      _lastLinkLoginId ??
                                                      _linkIdController.text
                                                          .trim();
                                                  if (loginId.isEmpty) {
                                                    _showError(
                                                      tr(
                                                        'msg.userfront.login.link.missing_phone',
                                                      ),
                                                    );
                                                    return;
                                                  }
                                                  _startEnchantedFlow(
                                                    loginId,
                                                    isEmail: false,
                                                    codeOnly: true,
                                                  );
                                                },
                                                child: Text(
                                                  tr(
                                                    'ui.userfront.login.link.code_only',
                                                    params: {
                                                      'time': _formatTime(
                                                        _linkResendSeconds,
                                                      ),
                                                    },
                                                  ),
                                                ),
                                              ),
                                            ],
                                          ],
                                        ],
                                      ],
                                    ),
                                  ),
                                ),
                              ),
                              Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                crossAxisAlignment: CrossAxisAlignment.center,
                                children: [
                                  if (_isQrLoading)
                                    const CircularProgressIndicator()
                                  else if (_qrExpired)
                                    Column(
                                      children: [
                                        Text(
                                          tr('msg.userfront.login.qr_expired'),
                                          textAlign: TextAlign.center,
                                          style: TextStyle(
                                            color: mutedColor,
                                            fontSize: 12,
                                          ),
                                        ),
                                        const SizedBox(height: 14),
                                        FilledButton(
                                          onPressed: _startQrFlow,
                                          child: Text(tr('ui.common.refresh')),
                                        ),
                                      ],
                                    )
                                  else if (_qrImageBase64 != null)
                                    Column(
                                      crossAxisAlignment:
                                          CrossAxisAlignment.center,
                                      children: [
                                        Container(
                                          padding: const EdgeInsets.all(18),
                                          decoration: BoxDecoration(
                                            border: Border.all(
                                              color: colorScheme.outline,
                                            ),
                                            borderRadius: BorderRadius.circular(
                                              18,
                                            ),
                                          ),
                                          child: QrImageView(
                                            data: _qrImageBase64!,
                                            version: QrVersions.auto,
                                            size: 200.0,
                                            backgroundColor: Colors.white,
                                          ),
                                        ),
                                        const SizedBox(height: 14),
                                        Text(
                                          _qrRemainingSeconds > 0
                                              ? tr(
                                                  'ui.userfront.login.qr.remaining',
                                                  params: {
                                                    'time': _formatTime(
                                                      _qrRemainingSeconds,
                                                    ),
                                                  },
                                                )
                                              : tr(
                                                  'ui.userfront.login.qr.expired',
                                                ),
                                          textAlign: TextAlign.center,
                                          style: TextStyle(
                                            color: _qrRemainingSeconds > 30
                                                ? primaryColor
                                                : Colors.red,
                                            fontWeight: FontWeight.bold,
                                          ),
                                        ),
                                        const SizedBox(height: 8),
                                        Text(
                                          tr(
                                            'msg.userfront.login.qr.scan_hint',
                                          ),
                                          textAlign: TextAlign.center,
                                          style: TextStyle(
                                            color: mutedColor,
                                            fontSize: 12,
                                            height: 1.5,
                                          ),
                                        ),
                                        TextButton(
                                          onPressed: _startQrFlow,
                                          child: Text(
                                            tr('ui.userfront.login.qr.refresh'),
                                          ),
                                        ),
                                      ],
                                    )
                                  else
                                    Text(
                                      tr('msg.userfront.login.qr.load_failed'),
                                      textAlign: TextAlign.center,
                                    ),
                                ],
                              ),
                            ],
                          ),
                        ),
                        const SizedBox(height: 18),
                        Column(
                          children: [
                            TextButton(
                              onPressed: () => context.push('/forgot-password'),
                              child: Text(
                                tr('ui.userfront.login.forgot_password'),
                              ),
                            ),
                            Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              children: [
                                Text(
                                  tr('msg.userfront.login.no_account'),
                                  style: TextStyle(
                                    color: mutedColor,
                                    fontSize: 14,
                                  ),
                                ),
                                TextButton(
                                  onPressed: () => context.push('/signup'),
                                  child: Text(tr('ui.userfront.login.signup')),
                                ),
                              ],
                            ),
                          ],
                        ),
                        const SizedBox(height: 12),
                        const Wrap(
                          alignment: WrapAlignment.center,
                          spacing: 10,
                          runSpacing: 10,
                          children: [ThemeToggleButton(), LanguageSelector()],
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}
