import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../models/motorcycle_models.dart'; import '../../core/theme/theme_extensions.dart'; import '../../services/entitlements/entitlement_providers.dart'; import '../../services/entitlements/feature_access_service.dart'; import '../entitlements/widgets/pro_lock_badge.dart'; import 'garage_providers.dart'; import 'widgets/motorcycle_photo.dart'; class AddMotorcycleScreen extends ConsumerStatefulWidget { const AddMotorcycleScreen({super.key}); @override ConsumerState createState() => _AddMotorcycleScreenState(); } class _AddMotorcycleScreenState extends ConsumerState { int _step = 1; // 1: Year, 2: Make, 3: Model, 4: Variant, 5: Confirm int? _selectedYear; MotorcycleMake? _selectedMake; MotorcycleModel? _selectedModel; MotorcycleVariant? _selectedVariant; MotorcycleSpecification? _previewSpec; final TextEditingController _nicknameController = TextEditingController(); final TextEditingController _searchController = TextEditingController(); bool _isLoading = false; List _years = []; List _makes = []; List _models = []; List _variants = []; @override void initState() { super.initState(); _loadYears(); } @override void dispose() { _nicknameController.dispose(); _searchController.dispose(); super.dispose(); } Future _loadYears() async { setState(() => _isLoading = true); final repo = ref.read(motorcycleRepositoryProvider); final years = await repo.getYears(); setState(() { _years = years; _isLoading = false; }); } Future _selectYear(int year) async { setState(() { _selectedYear = year; _step = 2; _isLoading = true; _searchController.clear(); }); final repo = ref.read(motorcycleRepositoryProvider); final makes = await repo.getMakes(year); setState(() { _makes = makes; _isLoading = false; }); } Future _selectMake(MotorcycleMake make) async { setState(() { _selectedMake = make; _step = 3; _isLoading = true; _searchController.clear(); }); final repo = ref.read(motorcycleRepositoryProvider); final models = await repo.getModels(_selectedYear!, make.id); setState(() { _models = models; _isLoading = false; }); } Future _selectModel(MotorcycleModel model) async { setState(() { _selectedModel = model; _isLoading = true; }); final repo = ref.read(motorcycleRepositoryProvider); final variants = await repo.getVariants( _selectedYear!, _selectedMake!.id, model.id, ); if (variants.length <= 1) { _selectedVariant = variants.isNotEmpty ? variants.first : null; await _loadSpecSummary(); } else { setState(() { _variants = variants; _step = 4; _isLoading = false; }); } } Future _selectVariant(MotorcycleVariant variant) async { setState(() => _selectedVariant = variant); await _loadSpecSummary(); } Future _loadSpecSummary() async { setState(() => _isLoading = true); final selection = MotorcycleSelection( year: _selectedYear!, makeId: _selectedMake!.id, makeName: _selectedMake!.name, modelId: _selectedModel!.id, modelName: _selectedModel!.name, variantId: _selectedVariant?.id, variantName: _selectedVariant?.name, ); final repo = ref.read(motorcycleRepositoryProvider); final spec = await repo.getSpecifications(selection); setState(() { _previewSpec = spec; _step = 5; _isLoading = false; }); } Future _saveMotorcycle() async { final bikes = ref.read(garageMotorcyclesStreamProvider).value ?? []; if (bikes.isNotEmpty) { final canAddMore = ref .read(featureAccessProvider) .canAccess(MotorSignalFeature.useMultipleMotorcycles); if (!canAddMore) { showProUpgradeSheet( context, ref, feature: MotorSignalFeature.useMultipleMotorcycles, ); return; } } final selection = MotorcycleSelection( year: _selectedYear!, makeId: _selectedMake!.id, makeName: _selectedMake!.name, modelId: _selectedModel!.id, modelName: _selectedModel!.name, variantId: _selectedVariant?.id, variantName: _selectedVariant?.name, ); final controller = ref.read(garageControllerProvider); await controller.addMotorcycle( selection, nickname: _nicknameController.text.trim().isNotEmpty ? _nicknameController.text.trim() : null, ); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Added ${selection.displayName} to your Garage!'), ), ); context.pop(); } } void _goBack() { if (_step > 1) { setState(() { _step -= 1; _searchController.clear(); }); } else { context.pop(); } } @override Widget build(BuildContext context) { final colors = context.motorColors; return PopScope( canPop: _step == 1, onPopInvokedWithResult: (didPop, result) { if (!didPop && _step > 1) _goBack(); }, child: Scaffold( appBar: AppBar( title: Text( _getStepTitle(), style: const TextStyle(fontWeight: FontWeight.bold), ), leading: IconButton( icon: const Icon(Icons.arrow_back), onPressed: _goBack, ), ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : Column( children: [ LinearProgressIndicator( value: _step / 5.0, backgroundColor: colors.outlineVariant, valueColor: AlwaysStoppedAnimation(colors.cyberCyan), ), Expanded(child: _buildStepContent(colors)), ], ), ), ); } String _getStepTitle() { switch (_step) { case 1: return 'Select Year'; case 2: return 'Select Manufacturer'; case 3: return 'Select Model (${_selectedMake?.name ?? ""})'; case 4: return 'Select Variant'; case 5: return 'Confirm Motorcycle'; default: return 'Add Motorcycle'; } } Widget _buildStepContent(MotorSignalThemeColors colors) { switch (_step) { case 1: return _buildYearStep(colors); case 2: return _buildMakeStep(colors); case 3: return _buildModelStep(colors); case 4: return _buildVariantStep(colors); case 5: return _buildConfirmStep(colors); default: return const SizedBox.shrink(); } } Widget _buildYearStep(MotorSignalThemeColors colors) { final theme = Theme.of(context); return GridView.builder( padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 2.2, crossAxisSpacing: 10, mainAxisSpacing: 10, ), itemCount: _years.length, itemBuilder: (context, index) { final year = _years[index].year; final isSelected = _selectedYear == year; return OutlinedButton( style: OutlinedButton.styleFrom( side: BorderSide( color: isSelected ? colors.cyberCyan : colors.outlineVariant, width: isSelected ? 2 : 1, ), backgroundColor: isSelected ? colors.cyberCyan.withValues(alpha: 0.2) : colors.surfaceContainer, ), onPressed: () => _selectYear(year), child: Text( '$year', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 16, fontFamily: 'JetBrains Mono', color: isSelected ? colors.cyberCyan : theme.colorScheme.onSurface, ), ), ); }, ); } Widget _buildMakeStep(MotorSignalThemeColors colors) { final query = _searchController.text.toLowerCase(); final filtered = _makes .where((m) => m.name.toLowerCase().contains(query)) .toList(); final theme = Theme.of(context); return Column( children: [ Padding( padding: const EdgeInsets.all(16.0), child: TextField( controller: _searchController, decoration: InputDecoration( hintText: 'Search Manufacturer...', prefixIcon: Icon(Icons.search, color: colors.cyberCyan), filled: true, fillColor: colors.surfaceContainer, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: colors.outlineVariant), ), ), onChanged: (_) => setState(() {}), ), ), Expanded( child: ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: filtered.length, separatorBuilder: (_, _) => Divider(height: 1, color: colors.outlineVariant), itemBuilder: (context, index) { final make = filtered[index]; return ListTile( title: Text( make.name, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 17, color: theme.colorScheme.onSurface, ), ), trailing: Icon( Icons.chevron_right, color: theme.colorScheme.onSurface.withValues(alpha: 0.3), ), onTap: () => _selectMake(make), ); }, ), ), ], ); } Widget _buildModelStep(MotorSignalThemeColors colors) { final query = _searchController.text.toLowerCase(); final filtered = _models .where((m) => m.name.toLowerCase().contains(query)) .toList(); final theme = Theme.of(context); return Column( children: [ Padding( padding: const EdgeInsets.all(16.0), child: TextField( controller: _searchController, decoration: InputDecoration( hintText: 'Search Model...', prefixIcon: Icon(Icons.search, color: colors.cyberCyan), filled: true, fillColor: colors.surfaceContainer, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: colors.outlineVariant), ), ), onChanged: (_) => setState(() {}), ), ), Expanded( child: ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16), itemCount: filtered.length, separatorBuilder: (_, _) => Divider(height: 1, color: colors.outlineVariant), itemBuilder: (context, index) { final model = filtered[index]; return ListTile( title: Text( model.name, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 17, color: theme.colorScheme.onSurface, ), ), subtitle: Text( '$_selectedYear ${_selectedMake?.name}', style: TextStyle( color: theme.colorScheme.onSurface.withValues(alpha: 0.5), ), ), trailing: Icon( Icons.chevron_right, color: theme.colorScheme.onSurface.withValues(alpha: 0.3), ), onTap: () => _selectModel(model), ); }, ), ), ], ); } Widget _buildVariantStep(MotorSignalThemeColors colors) { final theme = Theme.of(context); return ListView.separated( padding: const EdgeInsets.all(16), itemCount: _variants.length, separatorBuilder: (_, _) => const SizedBox(height: 12), itemBuilder: (context, index) { final variant = _variants[index]; return Card( color: colors.surfaceContainer, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), side: BorderSide(color: colors.outlineVariant), ), child: ListTile( title: Text( variant.name, style: TextStyle( fontWeight: FontWeight.bold, fontSize: 17, color: theme.colorScheme.onSurface, ), ), trailing: Icon( Icons.check_circle_outline, color: colors.cyberCyan, ), onTap: () => _selectVariant(variant), ), ); }, ); } Widget _buildConfirmStep(MotorSignalThemeColors colors) { final spec = _previewSpec; final theme = Theme.of(context); return SingleChildScrollView( padding: const EdgeInsets.all(20.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(16), border: Border.all(color: colors.cyberCyan, width: 2), ), child: Column( children: [ MotorcyclePhoto( year: _selectedYear!, make: _selectedMake!.name, model: _selectedModel!.name, height: 200, borderRadius: BorderRadius.circular(10), ), const SizedBox(height: 14), Text( '$_selectedYear ${_selectedMake?.name} ${_selectedModel?.name}', textAlign: TextAlign.center, style: TextStyle( fontFamily: 'Sora', fontSize: 20, fontWeight: FontWeight.bold, color: theme.colorScheme.onSurface, ), ), if (_selectedVariant?.name != null && _selectedVariant!.name != 'Standard') ...[ const SizedBox(height: 4), Text( _selectedVariant!.name, style: TextStyle( color: theme.colorScheme.onSurface.withValues(alpha: 0.7), fontSize: 15, ), ), ], ], ), ), const SizedBox(height: 20), if (spec != null) ...[ Text( 'SPECIFICATION SUMMARY', style: TextStyle( fontFamily: 'Sora', color: colors.cyberCyan, fontWeight: FontWeight.bold, letterSpacing: 1.0, fontSize: 13, ), ), const SizedBox(height: 10), Row( children: [ Expanded( child: _buildSpecChip( 'DISPLACEMENT', spec.displacementCc != null ? '${spec.displacementCc!.toStringAsFixed(0)} cc' : '—', colors, theme, ), ), const SizedBox(width: 10), Expanded( child: _buildSpecChip( 'HORSEPOWER', spec.horsepower != null ? '${spec.horsepower!.toStringAsFixed(0)} HP' : '—', colors, theme, ), ), ], ), const SizedBox(height: 10), Row( children: [ Expanded( child: _buildSpecChip( 'TORQUE', spec.torqueLbFt != null ? '${spec.torqueLbFt!.toStringAsFixed(1)} lb-ft' : '—', colors, theme, ), ), const SizedBox(width: 10), Expanded( child: _buildSpecChip( 'WET WEIGHT', spec.wetWeightLbs != null ? '${spec.wetWeightLbs!.toStringAsFixed(0)} lbs' : '—', colors, theme, ), ), ], ), const SizedBox(height: 20), ], TextField( controller: _nicknameController, decoration: InputDecoration( labelText: 'Nickname (Optional)', hintText: 'e.g., Blue Beast, The Track Bike', filled: true, fillColor: colors.surfaceContainer, border: OutlineInputBorder( borderRadius: BorderRadius.circular(10), borderSide: BorderSide(color: colors.outlineVariant), ), prefixIcon: Icon(Icons.edit, color: colors.cyberCyan), ), ), const SizedBox(height: 24), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: colors.cyberCyan, foregroundColor: Colors.black, padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), onPressed: _saveMotorcycle, child: const Text( 'ADD TO GARAGE', style: TextStyle( fontFamily: 'Sora', fontSize: 16, fontWeight: FontWeight.bold, letterSpacing: 1.2, ), ), ), ], ), ); } Widget _buildSpecChip( String label, String value, MotorSignalThemeColors colors, ThemeData theme, ) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(10), border: Border.all(color: colors.outlineVariant), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: TextStyle( fontSize: 9.5, color: theme.colorScheme.onSurface.withValues(alpha: 0.5), letterSpacing: 0.8, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 4), Text( value, style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, fontFamily: 'JetBrains Mono', color: theme.colorScheme.onSurface, ), ), ], ), ); } }