import "package:flutter/material.dart";
import "package:intl/date_symbol_data_local.dart";

import "api.dart";
import "app_settings.dart";
import "auth.dart";
import "biometric.dart";
import "i18n.dart";
import "servers.dart";
import "theme.dart";
import "screens/lock_screen.dart";
import "screens/login_screen.dart";
import "screens/root_shell.dart";

// Simple app-wide singletons (small app — no DI framework needed).
final apiClient = ApiClient();
final authService = AuthService(apiClient);
final appSettings = AppSettings();

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // Month and day names are rendered in the user's chosen language, so every
  // locale's date symbols have to be loaded before the first formatDate call —
  // DateFormat throws on an uninitialized locale rather than falling back.
  await initializeDateFormatting();
  // Load the UI translation files before the first frame so t() is ready.
  await loadTranslations();
  // The servers the app can read from, and the session held for each — read
  // before anything else so the first request knows where to go.
  await serverRegistry.load();
  await appSettings.loadFromStorage();
  await authService.loadFromStorage();
  // Prime the biometric-enabled cache; if a session survived from a previous
  // run and biometric login is on, start locked so the app requires an unlock
  // instead of jumping straight to the dashboard.
  final bioEnabled = await biometricAuth.isEnabled();
  if (authService.isAuthenticated && bioEnabled) {
    authService.lock();
  }
  // If a token survived from a previous run, refresh the profile so the saved
  // appearance prefs (theme/font/date format) apply on boot.
  if (authService.isAuthenticated) {
    apiClient.getMe().then((p) => appSettings.applyFromProfile(p)).catchError((_) {});
  }
  runApp(const CarControlApp());
}

class CarControlApp extends StatefulWidget {
  const CarControlApp({super.key});
  @override
  State<CarControlApp> createState() => _CarControlAppState();
}

class _CarControlAppState extends State<CarControlApp> with WidgetsBindingObserver {
  // Grace period: a quick app-switch (returning within this window) does NOT
  // re-lock; staying in the background longer does.
  static const _lockGrace = Duration(seconds: 30);
  DateTime? _backgroundedAt;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    // Re-lock when the app returns from the background, but only if it was away
    // longer than the grace period — so quick app-switches don't re-lock.
    // Handle only 'paused'/'resumed' (not 'inactive', which also fires
    // transiently while the OS biometric prompt is showing).
    if (state == AppLifecycleState.paused) {
      _backgroundedAt = DateTime.now();
    } else if (state == AppLifecycleState.resumed) {
      final since = _backgroundedAt;
      _backgroundedAt = null;
      if (since != null &&
          DateTime.now().difference(since) > _lockGrace &&
          authService.isAuthenticated &&
          biometricAuth.enabledCached) {
        authService.lock();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return ListenableBuilder(
      listenable: appSettings,
      builder: (context, _) => MaterialApp(
        title: "DriverVault",
        debugShowCheckedModeBanner: false,
        theme: DriverVault.theme(Brightness.light),
        darkTheme: DriverVault.theme(Brightness.dark),
        themeMode: appSettings.themeMode,
        // Apply the user's font-size preference app-wide.
        builder: (context, child) => MediaQuery(
          data: MediaQuery.of(context).copyWith(
            textScaler: TextScaler.linear(appSettings.textScale),
          ),
          child: child!,
        ),
        home: ListenableBuilder(
          listenable: authService,
          builder: (context, _) {
            if (!authService.isAuthenticated) return const LoginScreen();
            if (authService.locked) return const LockScreen();
            // Keyed on the active server: switching servers swaps the garage,
            // the charging page and the settings together, and a fresh shell is
            // what makes every one of them re-read from the new one rather than
            // keep showing the cars of the old.
            return RootShell(key: ValueKey(serverRegistry.activeId));
          },
        ),
      ),
    );
  }
}
