import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flux/core/blocs/session/session_cubit.dart'; import 'package:flux/core/data/core_repository.dart'; import 'package:flux/core/layout/app_shell.dart'; import 'package:flux/core/utils/extensions.dart'; import 'package:flux/core/widgets/set_password_screen.dart'; import 'package:flux/core/widgets/shared_forms/mobile_upload_screen.dart'; import 'package:flux/features/auth/ui/auth_screen.dart'; import 'package:flux/features/customers/blocs/customers_cubit.dart'; import 'package:flux/features/customers/models/customer_model.dart'; import 'package:flux/features/customers/ui/customer_detail_screen.dart'; import 'package:flux/features/customers/ui/customers_content.dart'; import 'package:flux/features/home/ui/home_screen.dart'; import 'package:flux/features/master_data/master_data_hub_content.dart'; import 'package:flux/features/master_data/products/blocs/product_cubit.dart'; import 'package:flux/features/master_data/products/ui/products_screen.dart'; import 'package:flux/features/master_data/providers/blocs/provider_cubit.dart'; import 'package:flux/features/master_data/providers/ui/providers_master_data_screen.dart'; import 'package:flux/features/master_data/staff/blocs/staff_cubit.dart'; import 'package:flux/features/master_data/staff/ui/staff_screen.dart'; import 'package:flux/features/master_data/store/ui/stores_screen.dart'; import 'package:flux/features/onboarding/blocs/onboarding_cubit.dart'; import 'package:flux/features/onboarding/ui/onboarding_screen.dart'; import 'package:flux/features/attachments/blocs/attachments_bloc.dart'; import 'package:flux/features/operations/models/operation_model.dart'; import 'package:flux/features/operations/ui/operation_form_screen.dart'; import 'package:flux/features/operations/ui/operations_screen.dart'; import 'package:flux/features/tickets/blocs/ticket_form_cubit.dart'; import 'package:flux/features/tickets/blocs/ticket_list_cubit.dart'; import 'package:flux/features/tickets/models/ticket_model.dart'; import 'package:flux/features/tickets/ui/ticket_form_screen.dart'; import 'package:flux/features/tickets/ui/ticket_list_screen.dart'; import 'package:get_it/get_it.dart'; import 'package:go_router/go_router.dart'; // Nota: Dovrai creare questi placeholder o file per non avere errori di compilazione // import 'package:flux/features/master_data/master_data_hub_screen.dart'; // import 'package:flux/features/master_data/staff/ui/staff_screen.dart'; // import 'package:flux/features/master_data/store/ui/stores_screen.dart'; class AppRouter { static GoRouter createRouter(SessionCubit sessionCubit) { return GoRouter( initialLocation: '/', refreshListenable: GoRouterRefreshStream(sessionCubit.stream), redirect: (context, state) { final sessionState = sessionCubit.state; final isGoingToLogin = state.matchedLocation == '/login'; final isGoingToOnboarding = state.matchedLocation == '/onboarding'; final isGoingToSetPassword = state.matchedLocation == '/set-password'; if (sessionState.status == SessionStatus.initial) return null; if (sessionState.status == SessionStatus.unauthenticated) { if (isGoingToLogin || isGoingToSetPassword) return null; return '/login'; } if (sessionState.status == SessionStatus.onboardingRequired) { return isGoingToOnboarding ? null : '/onboarding'; } if (sessionState.status == SessionStatus.authenticated) { if (isGoingToLogin || isGoingToOnboarding) return '/'; return null; } return null; }, routes: [ // --- ROTTE DI SERVIZIO (FUORI DALLA SHELL) --- GoRoute( path: '/login', builder: (context, state) => const AuthScreen(), ), GoRoute( path: '/set-password', builder: (context, state) => const SetPasswordScreen(), ), GoRoute( path: '/onboarding', builder: (context, state) => BlocProvider( create: (context) => OnboardingCubit( GetIt.I.get(), GetIt.I.get(), ), child: const OnboardingScreen(), ), ), // --- CORE APP (DENTRO LA SHELL CON NAVIGATION BAR/RAIL) --- ShellRoute( builder: (context, state, child) => AppShell(child: child), routes: [ // 1. DASHBOARD GoRoute(path: '/', builder: (context, state) => const HomeScreen()), // 2. HUB ANAGRAFICHE E SOTTO-ROTTE GoRoute( path: '/master-data', builder: (context, state) => const MasterDataHubScreen(), routes: [ GoRoute( path: 'products', // Diventa /master-data/products builder: (context, state) { context.read().refreshCubit(); return const ProductsScreen(); }, ), GoRoute( path: 'staff', // Diventa /master-data/staff builder: (context, state) => const StaffScreen(), ), GoRoute( path: 'stores', // Diventa /master-data/stores builder: (context, state) => const StoresScreen(), ), GoRoute( path: 'providers', // Diventa /master-data/providers builder: (context, state) => const ProvidersMasterDataScreen(), ), ], ), // 3. IMPOSTAZIONI GoRoute( path: '/settings', builder: (context, state) => Scaffold( appBar: AppBar(title: Text(context.l10n.commonSettings)), body: Center( child: ElevatedButton.icon( onPressed: () => context.read().signOut(), icon: const Icon(Icons.logout), label: const Text("Esci da FLUX"), ), ), ), ), GoRoute( path: '/operations', builder: (context, state) => const OperationsScreen(), ), GoRoute( path: '/customers', builder: (context, state) => const CustomersContent(), // O come si chiama il tuo widget della lista! ), GoRoute( path: '/tickets', builder: (context, state) => BlocProvider( create: (context) => TicketListCubit(), child: const TicketListScreen(), ), ), ], ), // --- DETTAGLI E OPERATIVITÀ (FUORI DALLA SHELL - TUTTO SCHERMO) --- GoRoute( // Il path sarà es. /tickets/form/123 oppure /tickets/form/new path: '/tickets/form/:id', builder: (context, state) { // 1. Leggiamo l'ID dall'URL final String pathId = state.pathParameters['id'] ?? 'new'; // 2. Leggiamo l'oggetto dalla RAM (se arriviamo da un tap interno all'app) final TicketModel? ticketFromExtra = state.extra as TicketModel?; // 3. Capiamo se è un nuovo ticket o una modifica final String? realTicketId = pathId == 'new' ? null : pathId; context.read().loadStaffForStore( GetIt.I.get().state.currentStore!.id!, ); context.read().loadCustomers(); return MultiBlocProvider( providers: [ BlocProvider( create: (context) => AttachmentsBloc( parentType: AttachmentParentType.ticket, parentId: realTicketId, ), ), BlocProvider(create: (context) => TicketFormCubit()), ], child: TicketFormScreen( ticketId: realTicketId, existingTicket: ticketFromExtra, ), ); }, ), GoRoute( path: '/customer/:id', builder: (context, state) { final customer = state.extra as CustomerModel; return BlocProvider( create: (context) => AttachmentsBloc( parentType: AttachmentParentType.customer, parentId: customer.id, ), child: CustomerDetailScreen(customer: customer), ); }, ), /* GoRoute( path: '/customer/:id/upload', builder: (context, state) { final customerId = state.pathParameters['id']!; final customerName = state.uri.queryParameters['name'] ?? 'Cliente'; return BlocProvider( create: (context) => AttachmentsBloc( parentType: AttachmentParentType.customer, parentId: customerId, ), child: SharedMobileUploadScreen( title: 'Aggiungi allegati al cliente $customerName', ), ); }, ), */ GoRoute( path: '/operation-form', name: 'operation-form', builder: (context, state) { final existingOperation = state.extra as OperationModel?; final operationId = state.uri.queryParameters['operationId']; final currentStoreId = GetIt.I .get() .state .currentStore! .id!; context.read().loadCustomers(); context.read().loadActiveProvidersForStore( currentStoreId, ); context.read().loadModels(); context.read().loadBrands(); context.read().loadStaffForStore(currentStoreId); return BlocProvider( create: (context) => AttachmentsBloc( parentId: operationId ?? existingOperation?.id, parentType: AttachmentParentType.operation, ), child: OperationFormScreen( operationId: operationId ?? existingOperation?.id, existingOperation: existingOperation, ), ); }, ), /* GoRoute( path: '/operation/:id/upload', builder: (context, state) { final operationId = state.pathParameters['id']!; final operationName = state.uri.queryParameters['name'] ?? 'Pratica'; final currentStoreId = GetIt.I .get() .state .currentStore! .id!; context.read().loadCustomers(); context.read().loadActiveProvidersForStore( currentStoreId, ); context.read().loadModels(); context.read().loadBrands(); context.read().loadStaffForStore(currentStoreId); return BlocProvider( create: (context) => AttachmentsBloc( parentId: operationId, parentType: AttachmentParentType.operation, ), child: SharedMobileUploadScreen( title: 'Aggiungi allegati alla pratica $operationName', ), ); }, ), */ GoRoute( path: '/upload/:type/:id', builder: (context, state) { final typeString = state.pathParameters['type']!; final id = state.pathParameters['id']!; // Trasformiamo la stringa dell'URL nel nostro amato Enum! final parentType = AttachmentParentType.values.firstWhere( (e) => e.name == typeString, orElse: () => AttachmentParentType.ticket, // Fallback di sicurezza ); // Creiamo il BLoC "al volo" solo per questa schermata return BlocProvider( create: (context) => AttachmentsBloc(parentId: id, parentType: parentType), child: const SharedMobileUploadScreen( title: 'Caricamento Rapido', ), ); }, ), ], ); } } class GoRouterRefreshStream extends ChangeNotifier { GoRouterRefreshStream(Stream stream) { notifyListeners(); _subscription = stream.asBroadcastStream().listen( (dynamic _) => notifyListeners(), ); } late final StreamSubscription _subscription; @override void dispose() { _subscription.cancel(); super.dispose(); } }