// ignore_for_file: avoid_print
import 'dart:async';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:easy_localization/easy_localization.dart' hide tr;
import 'package:go_router/go_router.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'features/auth/presentation/login_screen.dart';
import 'features/auth/presentation/signup_screen.dart';
import 'features/auth/presentation/approve_qr_screen.dart';
import 'features/auth/presentation/qr_scan_screen.dart';
import 'features/auth/presentation/forgot_password_screen.dart';
import 'features/auth/presentation/reset_password_screen.dart';
import 'features/auth/presentation/error_screen.dart';
import 'features/auth/domain/login_link_route_policy.dart';
import 'features/auth/domain/verification_completion_route.dart';
import 'features/dashboard/presentation/dashboard_screen.dart';
import 'features/admin/presentation/user_management_screen.dart';
import 'features/profile/presentation/pages/profile_page.dart';
import 'core/services/auth_proxy_service.dart';
import 'core/services/auth_token_store.dart';
import 'core/services/logger_service.dart';
import 'core/services/null_check_recovery.dart';
import 'core/services/web_window.dart';
import 'core/notifiers/auth_notifier.dart';
import 'core/theme/app_theme.dart';
import 'core/theme/theme_controller.dart';
import 'core/theme/theme_scope.dart';
import 'core/i18n/locale_gate.dart';
import 'core/i18n/locale_registry.dart';
import 'core/i18n/locale_utils.dart';
import 'core/i18n/toml_asset_loader.dart';
import 'core/ui/toast_service.dart';
import 'package:logging/logging.dart';
import 'features/auth/presentation/consent_screen.dart';
import 'i18n.dart';

final _log = Logger('Main');

Map<String, dynamic>? _decodeErrorDetails(String? raw) {
  if (raw == null || raw.trim().isEmpty) {
    return null;
  }
  try {
    final decoded = jsonDecode(raw);
    if (decoded is Map<String, dynamic>) {
      return decoded;
    }
  } catch (_) {}
  return null;
}

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

String? _redirectPrivateLocaleRoute(GoRouterState state) {
  if (_hasActiveLocalSession()) {
    return null;
  }
  final localeCode =
      extractLocaleFromPath(state.uri) ?? resolvePreferredLocaleCode();
  return buildSigninRedirectPath(localeCode, state.uri);
}

void _attemptRecoveryFromNullCheck({
  required Object exception,
  StackTrace? stackTrace,
}) {
  final uri = Uri.base;
  final target = computeNullCheckRecoveryTarget(
    exception: exception,
    uri: uri,
    preferredLocaleCode: resolvePreferredLocaleCode(),
  );
  if (target == null) {
    return;
  }
  final path = uri.path;

  AuthProxyService.logError(
    'RECOVERY_NAV_NULL_CHECK path=$path target=$target uri=$uri',
    error: exception,
    stackTrace: stackTrace,
  );
  webWindow.redirectTo(target);
}

Future<void> _silentSessionRecovery() async {
  _log.info("[SessionRecovery] Starting silent session recovery check...");

  // 1. Local token check
  final hasLocalToken = AuthTokenStore.hasToken();
  if (hasLocalToken) {
    _log.info("[SessionRecovery] Local token found. Verifying session...");
    try {
      final status = await AuthProxyService.getSessionStatus(
        token: AuthTokenStore.getToken(),
        useCookie: false,
      );
      if (status == 401 || status == 403) {
        _log.warning(
          "[SessionRecovery] Local token is invalid. Clearing store.",
        );
        AuthTokenStore.clear();
        return;
      }
      _log.info(
        "[SessionRecovery] Local token is valid. Skipping cookie check.",
      );
      return;
    } catch (e) {
      _log.info("[SessionRecovery] Failed to verify local token: $e");
      // 만약 네트워크 에러 등이라면 당장 로그아웃 시키지 않고 일단 통과시킬 수도 있지만,
      // 보안과 확실한 상태 갱신을 위해 여기서는 실패 시 상태를 유지하거나 필요에 따라 처리합니다.
      // (현재는 401/403 확실한 인증 실패시에만 clear 처리)
      return;
    }
  }

  _log.info(
    "[SessionRecovery] Local token missing. Checking for browser cookies...",
  );

  try {
    // 2. Try fetching user info (backend will use cookies if present)
    final userInfo = await AuthProxyService.getMe();
    final subject = userInfo['id'] ?? userInfo['identity_id'] ?? '';

    if (subject.isNotEmpty) {
      _log.info(
        "[SessionRecovery] Valid session found via cookies. Recovering login state...",
      );
      // For cookie-based auth, we don't necessarily have a JWT in local storage,
      // but AuthNotifier needs to know we are logged in.
      final jwt =
          userInfo['sessionJwt'] ?? userInfo['token'] ?? 'cookie-session';
      await AuthNotifier.instance.onLoginSuccess(jwt);
      _log.info("[SessionRecovery] Recovery complete. Subject: $subject");
    } else {
      _log.warning("[SessionRecovery] Session found but subject is empty.");
      AuthTokenStore.clear();
    }
  } catch (e) {
    _log.info(
      "[SessionRecovery] No valid cookie session found or request failed: $e",
    );
    AuthTokenStore.clear();
  }
}

bool _shouldRunStartupSessionRecovery(Uri uri) {
  final requestedLocale = extractLocaleFromPath(uri);
  final path = stripLocalePath(uri);
  final verificationPayloadRedirect = buildDedicatedVerificationRedirect(
    uri,
    localeCode: requestedLocale ?? resolvePreferredLocaleCode(),
  );
  if (verificationPayloadRedirect != null ||
      isDedicatedVerificationRoute(uri) ||
      path == verificationCompletionRoutePath) {
    return false;
  }
  if (requestedLocale == null) {
    return true;
  }
  return !isPublicAuthPath(path, uri);
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  usePathUrlStrategy();
  await EasyLocalization.ensureInitialized();
  LocaleRegistry.primeWithDefaults();

  // 1. Global Error Handling
  FlutterError.onError = (details) {
    FlutterError.presentError(details);
    _log.severe("FLUTTER_ERROR", details.exception, details.stack);
    // Also send to backend if needed
    AuthProxyService.logError(
      "FLUTTER_ERROR: ${details.exception}\n${details.stack}",
    );
    _attemptRecoveryFromNullCheck(
      exception: details.exception,
      stackTrace: details.stack,
    );
  };

  PlatformDispatcher.instance.onError = (error, stack) {
    _log.severe("PLATFORM_ERROR", error, stack);
    AuthProxyService.logError("PLATFORM_ERROR: $error\n$stack");
    _attemptRecoveryFromNullCheck(exception: error, stackTrace: stack);
    return true;
  };

  // 0. Initialize Logger
  LoggerService.init();

  runApp(
    // URL(/en, /ko)이 있으면 우선 적용해서 첫 렌더부터 올바른 언어로 시작합니다.
    () {
      final supportedLocaleCodes = LocaleRegistry.supportedLocaleCodes;
      final supportedLocales = supportedLocaleCodes
          .map((code) => Locale(code))
          .toList(growable: false);
      final fallbackLocaleCode = LocaleRegistry.fallbackLocaleCode;
      final initialLocaleCode =
          extractLocaleFromPath(Uri.base) ?? resolvePreferredLocaleCode();
      return EasyLocalization(
        supportedLocales: supportedLocales,
        fallbackLocale: Locale(fallbackLocaleCode),
        startLocale: Locale(initialLocaleCode),
        saveLocale: false,
        path: 'assets/translations',
        assetLoader: const TomlAssetLoader(),
        child: const ProviderScope(child: BaronSSOApp()),
      );
    }(),
  );
}

// Router Configuration
final _router = GoRouter(
  initialLocation: '/',
  debugLogDiagnostics: !kReleaseMode,
  refreshListenable: AuthNotifier.instance,
  routes: [
    GoRoute(
      path: '/',
      redirect: (context, state) {
        return buildLocalizedHomePath(
          state.uri,
          preferredLocaleCode: resolvePreferredLocaleCode(),
        );
      },
    ),
    ShellRoute(
      builder: (context, state, child) {
        final localeCode =
            extractLocaleFromPath(state.uri) ?? resolvePreferredLocaleCode();
        return LocaleGate(localeCode: localeCode, child: child);
      },
      routes: [
        GoRoute(
          path: '/:locale',
          builder: (context, state) {
            final rawLocale = state.pathParameters['locale'];
            final localeCode = normalizeLocaleCode(rawLocale);
            return ScopedTheme(
              controller: ThemeController.auth,
              child: LocaleEntryRedirectScreen(localeCode: localeCode),
            );
          },
          routes: [
            GoRoute(
              path: 'dashboard',
              redirect: (context, state) => _redirectPrivateLocaleRoute(state),
              builder: (context, state) {
                return ScopedTheme(
                  controller: ThemeController.app,
                  child: const DashboardScreen(),
                );
              },
            ),
            GoRoute(
              path: 'profile',
              redirect: (context, state) => _redirectPrivateLocaleRoute(state),
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.app,
                child: const ProfilePage(),
              ),
            ),
            GoRoute(
              path: 'signin',
              builder: (context, state) {
                final loginChallenge =
                    state.uri.queryParameters['login_challenge'];
                final redirectUrl =
                    state.uri.queryParameters['redirect_uri'] ??
                    state.uri.queryParameters['redirect_url'];
                return ScopedTheme(
                  controller: ThemeController.auth,
                  child: LoginScreen(
                    key: state.pageKey,
                    loginChallenge: loginChallenge,
                    redirectUrl: redirectUrl,
                  ),
                );
              },
            ),
            GoRoute(
              path: verificationCompletionRouteName,
              builder: (context, state) {
                return ScopedTheme(
                  controller: ThemeController.auth,
                  child: LoginScreen(
                    key: state.pageKey,
                    verificationCompleteOnly: true,
                  ),
                );
              },
            ),
            GoRoute(
              path: 'login',
              builder: (context, state) {
                // IMPORTANT: Match signin logic to handle OIDC challenges
                final loginChallenge =
                    state.uri.queryParameters['login_challenge'];
                final redirectUrl =
                    state.uri.queryParameters['redirect_uri'] ??
                    state.uri.queryParameters['redirect_url'];
                return ScopedTheme(
                  controller: ThemeController.auth,
                  child: LoginScreen(
                    key: state.pageKey,
                    loginChallenge: loginChallenge,
                    redirectUrl: redirectUrl,
                  ),
                );
              },
            ),
            GoRoute(
              path: 'consent',
              builder: (BuildContext context, GoRouterState state) {
                final consentChallenge =
                    state.uri.queryParameters['consent_challenge'];
                if (consentChallenge == null) {
                  return const Scaffold(
                    body: Center(
                      child: Text('Error: Consent challenge is missing.'),
                    ),
                  );
                }
                return ScopedTheme(
                  controller: ThemeController.auth,
                  child: ConsentScreen(consentChallenge: consentChallenge),
                );
              },
            ),
            GoRoute(
              path: 'signup',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: const SignupScreen(),
              ),
            ),
            GoRoute(
              path: 'registration',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: const SignupScreen(),
              ),
            ),
            GoRoute(
              path: 'verify',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: LoginScreen(key: state.pageKey),
              ),
            ),
            GoRoute(
              path: 'verify/:token',
              builder: (context, state) {
                final token = state.pathParameters['token'];
                return ScopedTheme(
                  controller: ThemeController.auth,
                  child: LoginScreen(
                    key: state.pageKey,
                    verificationToken: token,
                  ),
                );
              },
            ),
            GoRoute(
              path: 'verification',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: LoginScreen(key: state.pageKey),
              ),
            ),
            GoRoute(
              path: 'l/:shortCode',
              builder: (context, state) {
                return ScopedTheme(
                  controller: ThemeController.auth,
                  child: LoginScreen(key: state.pageKey),
                );
              },
            ),
            GoRoute(
              path: 'forgot-password',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: const ForgotPasswordScreen(),
              ),
            ),
            GoRoute(
              path: 'recovery',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: const ForgotPasswordScreen(),
              ),
            ),
            GoRoute(
              path: 'reset-password',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: const ResetPasswordScreen(),
              ),
            ),
            GoRoute(
              path: 'error',
              builder: (context, state) {
                final params = state.uri.queryParameters;
                return ScopedTheme(
                  controller: ThemeController.auth,
                  child: ErrorScreen(
                    errorId: params['id'],
                    errorCode: params['error'],
                    description:
                        params['error_description'] ?? params['message'],
                    tenantAccessDetails: _decodeErrorDetails(params['details']),
                  ),
                );
              },
            ),
            GoRoute(
              path: 'settings',
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: ErrorScreen(
                  errorCode: 'settings_disabled',
                  description: tr('msg.userfront.settings.disabled'),
                ),
              ),
            ),
            GoRoute(
              path: 'approve',
              redirect: (context, state) {
                final token = AuthTokenStore.getToken();
                final isLoggedIn =
                    (token != null && token.isNotEmpty) ||
                    AuthTokenStore.usesCookie();
                if (isLoggedIn) {
                  return null;
                }
                final localeCode =
                    extractLocaleFromPath(state.uri) ??
                    resolvePreferredLocaleCode();
                return '/$localeCode/signin?notice=qr_login_required';
              },
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: ApproveQrScreen(
                  pendingRef: state.uri.queryParameters['ref'],
                ),
              ),
            ),
            GoRoute(
              path: 'ql/:ref',
              redirect: (context, state) {
                final localeCode =
                    extractLocaleFromPath(state.uri) ??
                    resolvePreferredLocaleCode();
                final pendingRef = state.pathParameters['ref'];
                if (pendingRef == null || pendingRef.isEmpty) {
                  return '/$localeCode/approve';
                }
                final encodedRef = Uri.encodeQueryComponent(pendingRef);
                return '/$localeCode/approve?ref=$encodedRef';
              },
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: ApproveQrScreen(pendingRef: state.pathParameters['ref']),
              ),
            ),
            GoRoute(
              path: 'scan',
              redirect: (context, state) => _redirectPrivateLocaleRoute(state),
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.auth,
                child: const QRScanScreen(),
              ),
            ),
            GoRoute(
              path: 'admin/users',
              redirect: (context, state) => _redirectPrivateLocaleRoute(state),
              builder: (context, state) => ScopedTheme(
                controller: ThemeController.app,
                child: const UserManagementScreen(),
              ),
            ),
          ],
        ),
      ],
    ),
  ],
  redirect: (context, state) {
    final uri = state.uri;
    final requestedLocale = extractLocaleFromPath(uri);
    final preferredLocale = resolvePreferredLocaleCode();
    final verificationPayloadRedirect = buildDedicatedVerificationRedirect(
      uri,
      localeCode: requestedLocale ?? preferredLocale,
    );
    if (verificationPayloadRedirect != null) {
      return verificationPayloadRedirect;
    }

    if (requestedLocale == null) {
      final localizedPath = buildLocalizedPath(preferredLocale, uri);
      return localizedPath;
    }

    final token = AuthTokenStore.getToken();
    final isLoggedIn =
        (token != null && token.isNotEmpty) || AuthTokenStore.usesCookie();
    final path = stripLocalePath(uri);

    if (!isLoggedIn && (path == '/approve' || path.startsWith('/ql/'))) {
      return '/$requestedLocale/signin?notice=qr_login_required';
    }

    final isPublicPath = isPublicAuthPath(path, uri);

    if (isPublicPath) {
      return null;
    }

    if (!isLoggedIn) {
      if (path == '/') {
        return '/$requestedLocale/signin';
      }
      return buildSigninRedirectPath(requestedLocale, uri);
    }

    if (path == '/') {
      return '/$requestedLocale/dashboard';
    }

    return null;
  },
);

class BaronSSOApp extends StatefulWidget {
  const BaronSSOApp({super.key});

  @override
  State<BaronSSOApp> createState() => _BaronSSOAppState();
}

class _BaronSSOAppState extends State<BaronSSOApp> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      // Re-run router redirects after the first frame so session-only web
      // storage state is reflected even when startup routing evaluated too early.
      AuthNotifier.instance.notify();
      unawaited(LocaleRegistry.initialize());
      unawaited(ThemeController.app.restore());
      unawaited(ThemeController.auth.restore());
      if (_shouldRunStartupSessionRecovery(Uri.base)) {
        unawaited(_silentSessionRecovery());
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    final localization = EasyLocalization.of(context);
    final supportedLocales =
        localization?.supportedLocales ??
        LocaleRegistry.supportedLocaleCodes
            .map((code) => Locale(code))
            .toList(growable: false);
    final delegates = localization?.delegates ?? const [];
    final locale =
        localization?.currentLocale ?? Locale(resolvePreferredLocaleCode());

    return MaterialApp.router(
      title: tr('ui.userfront.app_title'),
      localizationsDelegates: delegates,
      supportedLocales: supportedLocales,
      locale: locale,
      builder: (context, child) {
        return Stack(
          children: [if (child != null) child, const ToastViewport()],
        );
      },
      theme: buildLightTheme(),
      darkTheme: buildDarkTheme(),
      themeMode: ThemeMode.light,
      routerConfig: _router,
    );
  }
}

class LocaleEntryRedirectScreen extends StatefulWidget {
  const LocaleEntryRedirectScreen({super.key, required this.localeCode});

  final String localeCode;

  @override
  State<LocaleEntryRedirectScreen> createState() =>
      _LocaleEntryRedirectScreenState();
}

class _LocaleEntryRedirectScreenState extends State<LocaleEntryRedirectScreen> {
  bool _redirected = false;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _redirect();
    });
  }

  void _redirect() {
    if (!mounted || _redirected) {
      return;
    }

    // This parent route is also built for nested locale routes, so only
    // redirect when the current location is exactly `/{locale}`.
    if (stripLocalePath(Uri.base) != '/') {
      return;
    }

    _redirected = true;
    if (!_hasActiveLocalSession()) {
      context.go('/${widget.localeCode}/signin');
      return;
    }
    context.go('/${widget.localeCode}/dashboard');
  }

  @override
  Widget build(BuildContext context) {
    return const Scaffold(body: Center(child: CircularProgressIndicator()));
  }
}
