import 'package:commons_core/commons_core.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:go_router/go_router.dart';

import 'data/species_repository.dart';
import 'data/variety_repository.dart';
import 'i18n/strings.g.dart';
import 'services/auto_backup_service.dart';
import 'services/coarse_location.dart';
import 'services/inbox_service.dart';
import 'services/message_store.dart';
import 'services/notification_service.dart';
import 'services/offer_outbox.dart';
import 'services/onboarding_store.dart';
import 'services/profile_cache.dart';
import 'services/profile_store.dart';
import 'services/social_account_store.dart';
import 'services/social_connection.dart';
import 'services/social_service.dart';
import 'services/social_settings.dart';
import 'services/trust_referents.dart';
import 'services/wot_settings.dart';
import 'state/inventory_cubit.dart';
import 'state/variety_detail_cubit.dart';
import 'ui/about_screen.dart';
import 'ui/auto_backup_gate.dart';
import 'ui/chat_list_screen.dart';
import 'ui/chat_screen.dart';
import 'ui/home_screen.dart';
import 'ui/intro_screen.dart';
import 'ui/inventory_list_screen.dart';
import 'ui/market_offer_detail_screen.dart';
import 'ui/market_screen.dart';
import 'ui/offline_banner.dart';
import 'ui/profile_screen.dart';
import 'ui/settings_screen.dart';
import 'ui/theme.dart';
import 'ui/trust_network_screen.dart';
import 'ui/variety_detail_screen.dart';

/// Root widget. Provides the repositories to the tree and wires go_router:
/// `/` is the home menu, `/inventory` the list, `/variety/:id` the item detail.
/// When [showIntro] is set (first launch), the app opens on `/intro`.
class TaneApp extends StatelessWidget {
  TaneApp({
    required this.repository,
    required this.species,
    required this.onboarding,
    this.social,
    this.socialSettings,
    this.connection,
    this.location,
    this.outbox,
    this.messageStore,
    this.profileStore,
    this.profileCache,
    this.socialAccounts,
    this.trustReferents,
    this.wotSettings,
    this.inbox,
    this.notifications,
    this.showIntro = false,
    this.autoBackup,
    super.key,
  }) : _router = _buildRouter(
          repository,
          onboarding,
          showIntro,
          social,
          socialSettings,
          connection,
          location,
          outbox,
          messageStore,
          profileStore,
          profileCache,
          socialAccounts,
          trustReferents,
          wotSettings,
          inbox,
        ) {
    // A tapped message notification opens that peer's chat. Wired here because
    // the router only exists now; taps only happen while the app is foreground,
    // so a live router reference is enough.
    notifications?.onTapChat = (pubkey) => _router.push('/chat/$pubkey');
  }

  final VarietyRepository repository;
  final SpeciesRepository species;
  final OnboardingStore onboarding;

  /// Block 2 social layer. Null until the social round is wired in `main`; when
  /// null the market stays a "coming soon" card and `/market` is not routed.
  final SocialService? social;
  final SocialSettings? socialSettings;

  /// The shared relay connection (one per identity) reused by every feature.
  final SocialConnection? connection;

  /// Optional device-location source for the market's "use my location".
  final CoarseLocationProvider? location;

  /// Optional offline outbox for the market's "share my seeds".
  final OfferOutbox? outbox;

  /// Optional persistence for chat history.
  final MessageStore? messageStore;

  /// Optional local store for your own profile (name/about).
  final ProfileStore? profileStore;

  /// Optional cache of peers' published display names.
  final ProfileCache? profileCache;

  /// Optional store of the active social identity, for the profile switcher.
  final SocialAccountStore? socialAccounts;

  /// Web-of-trust bootstrap referents + parameters (network membership).
  final TrustReferents? trustReferents;
  final WotSettings? wotSettings;

  /// App-wide inbox listener; drives the messages list's live refresh.
  final InboxService? inbox;

  /// OS notifications for foreground messages; its tap handler is wired to the
  /// router here. Null in tests / on platforms without notification support.
  final NotificationService? notifications;
  final bool showIntro;

  /// Drives silent periodic backups off the app lifecycle. Null in widget tests
  /// and on platforms without file storage (web) — the gate then does nothing.
  final AutoBackupService? autoBackup;
  final GoRouter _router;

  static GoRouter _buildRouter(
    VarietyRepository repository,
    OnboardingStore onboarding,
    bool showIntro,
    SocialService? social,
    SocialSettings? socialSettings,
    SocialConnection? connection,
    CoarseLocationProvider? location,
    OfferOutbox? outbox,
    MessageStore? messageStore,
    ProfileStore? profileStore,
    ProfileCache? profileCache,
    SocialAccountStore? socialAccounts,
    TrustReferents? trustReferents,
    WotSettings? wotSettings,
    InboxService? inbox,
  ) {
    return GoRouter(
      initialLocation: showIntro ? '/intro' : '/',
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) =>
              HomeScreen(marketEnabled: social != null),
        ),
        if (social != null && socialSettings != null && connection != null)
          GoRoute(
            path: '/market',
            builder: (context, state) => MarketScreen(
              social: social,
              settings: socialSettings,
              connection: connection,
              location: location,
              outbox: outbox,
            ),
          ),
        if (social != null && connection != null)
          GoRoute(
            path: '/market/offer',
            builder: (context, state) {
              final offer = state.extra as Offer;
              return MarketOfferDetailScreen(
                offer: offer,
                connection: connection,
                mine: offer.authorPubkeyHex == social.publicKeyHex,
                profileCache: profileCache,
              );
            },
          ),
        if (messageStore != null)
          GoRoute(
            path: '/messages',
            builder: (context, state) => ChatListScreen(
              store: messageStore,
              connection: connection,
              profileCache: profileCache,
              inbox: inbox,
            ),
          ),
        if (social != null &&
            connection != null &&
            profileStore != null &&
            socialAccounts != null)
          GoRoute(
            path: '/profile',
            builder: (context, state) => ProfileScreen(
              social: social,
              connection: connection,
              profileStore: profileStore,
              accounts: socialAccounts,
              trustNetworkEnabled:
                  trustReferents != null && wotSettings != null,
            ),
          ),
        if (trustReferents != null && wotSettings != null)
          GoRoute(
            path: '/trust',
            builder: (context, state) => TrustNetworkScreen(
              referents: trustReferents,
              wotSettings: wotSettings,
            ),
          ),
        if (social != null && connection != null)
          GoRoute(
            path: '/chat/:pubkey',
            builder: (context, state) => ChatScreen(
              social: social,
              connection: connection,
              peerPubkey: state.pathParameters['pubkey']!,
              messageStore: messageStore,
              profileCache: profileCache,
              trustReferents: trustReferents,
              wotSettings: wotSettings,
            ),
          ),
        GoRoute(
          path: '/intro',
          builder: (context, state) => IntroScreen(
            onDone: () async {
              await onboarding.markIntroSeen();
              if (context.mounted) context.go('/');
            },
          ),
        ),
        GoRoute(
          path: '/settings',
          builder: (context, state) => const SettingsScreen(),
        ),
        GoRoute(
          path: '/about',
          builder: (context, state) => const AboutScreen(),
        ),
        GoRoute(
          path: '/inventory',
          builder: (context, state) => BlocProvider(
            create: (_) => InventoryCubit(repository),
            child: const InventoryListScreen(),
          ),
        ),
        GoRoute(
          path: '/variety/:id',
          builder: (context, state) => BlocProvider(
            create: (_) =>
                VarietyDetailCubit(repository, state.pathParameters['id']!),
            child: const VarietyDetailScreen(),
          ),
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    return MultiRepositoryProvider(
      providers: [
        RepositoryProvider.value(value: repository),
        RepositoryProvider.value(value: species),
      ],
      child: AutoBackupGate(
        service: autoBackup,
        child: MaterialApp.router(
          onGenerateTitle: (context) => context.t.app.title,
          debugShowCheckedModeBanner: false,
          theme: buildTaneTheme(),
          // Let scrollables & PageViews be dragged with a mouse/trackpad on
          // desktop (Flutter disables that by default), so the photo carousel and
          // lists swipe there too.
          scrollBehavior: const _DragScrollBehavior(),
          // Flutter ships no Material/Cupertino localizations for Asturian
          // (`ast`), so render the framework chrome (date pickers, native dialog
          // buttons) in Spanish — the closest shipped language — while the app's
          // own text stays Asturian via slang. Every other locale maps 1:1.
          locale: materialLocaleFor(TranslationProvider.of(context).flutterLocale),
          supportedLocales: AppLocaleUtils.supportedLocales,
          localizationsDelegates: const [
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
            GlobalCupertinoLocalizations.delegate,
          ],
          // A global "you're offline" strip above every screen — makes it clear
          // why the social layer is paused (the inventory still works).
          builder: (context, child) =>
              OfflineBanner(child: child ?? const SizedBox.shrink()),
          routerConfig: _router,
        ),
      ),
    );
  }
}

/// Maps the app's active locale to one Flutter's bundled Material/Cupertino
/// localizations can serve. Asturian (`ast`) has none, so it borrows Spanish
/// (`es`) for the framework chrome; the app's own strings stay Asturian (they
/// come from slang, not from `Localizations`). All other locales pass through.
Locale materialLocaleFor(Locale locale) =>
    locale.languageCode == 'ast' ? const Locale('es') : locale;

/// Enables mouse/trackpad drag scrolling (off by default on desktop) so the
/// photo carousel and lists can be swiped with a pointer.
class _DragScrollBehavior extends MaterialScrollBehavior {
  const _DragScrollBehavior();

  @override
  Set<PointerDeviceKind> get dragDevices => {
    PointerDeviceKind.touch,
    PointerDeviceKind.mouse,
    PointerDeviceKind.trackpad,
    PointerDeviceKind.stylus,
  };
}
