import 'package:sysfarma_mobile/src/app/widgets/app_panel.dart'; import 'package:sysfarma_mobile/src/app/widgets/empty_state_panel.dart'; import 'package:sysfarma_mobile/src/core/network/api_client.dart'; import 'package:sysfarma_mobile/src/core/theme/app_tokens.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class CriticalStockReportScreen extends ConsumerStatefulWidget { const CriticalStockReportScreen({super.key}); @override ConsumerState createState() => _CriticalStockReportScreenState(); } class _CriticalStockReportScreenState extends ConsumerState { String _kind = 'all'; bool _isLoading = true; Map _data = const {}; @override void initState() { super.initState(); _refresh(); } Future _refresh() async { if (mounted) setState(() => _isLoading = true); final response = await ref.read(apiClientProvider).criticalStockReport(kind: _kind); if (!mounted) return; setState(() { _data = response.data ?? const {}; _isLoading = false; }); } void _setKind(String kind) { if (kind == _kind) return; setState(() => _kind = kind); _refresh(); } @override Widget build(BuildContext context) { final totals = Map.from(_data['totals'] as Map? ?? const {}); final items = List>.from(_data['items'] as List? ?? const []); final outCount = totals['out_of_stock'] ?? 0; final lowCount = totals['low_stock'] ?? 0; return SafeArea( child: RefreshIndicator( onRefresh: _refresh, child: ListView( padding: AppTokens.pagePadding, children: [ Row( children: [ Expanded( child: _SegmentChip( label: 'Todos', selected: _kind == 'all', onTap: () => _setKind('all'), ), ), const SizedBox(width: 8), Expanded( child: _SegmentChip( label: 'Sin stock', selected: _kind == 'out', onTap: () => _setKind('out'), ), ), const SizedBox(width: 8), Expanded( child: _SegmentChip( label: 'Bajo', selected: _kind == 'low', onTap: () => _setKind('low'), ), ), ], ), const SizedBox(height: 14), Row( children: [ Expanded( child: _StatCard( label: 'Sin stock', value: '$outCount', color: AppTokens.danger, icon: Icons.block_rounded, ), ), const SizedBox(width: 12), Expanded( child: _StatCard( label: 'Bajo stock', value: '$lowCount', color: AppTokens.warning, icon: Icons.trending_down_rounded, ), ), ], ), const SizedBox(height: 14), if (_isLoading) const Padding( padding: EdgeInsets.symmetric(vertical: 32), child: Center(child: CircularProgressIndicator()), ) else if (items.isEmpty) const EmptyStatePanel( icon: Icons.check_circle_outline_rounded, title: 'Sin productos críticos', subtitle: 'Todo el catálogo está por encima del mínimo.', ) else AppPanel( title: 'Productos', trailing: Text('${items.length}', style: Theme.of(context).textTheme.titleMedium?.copyWith( color: AppTokens.primary, fontWeight: FontWeight.w700)), child: Column( children: [ for (final item in items) ...[ _StockRow(item: item), if (item != items.last) const Divider(height: 16), ], ], ), ), ], ), ), ); } } class _SegmentChip extends StatelessWidget { const _SegmentChip( {required this.label, required this.selected, required this.onTap}); final String label; final bool selected; final VoidCallback onTap; @override Widget build(BuildContext context) { return Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(AppTokens.radiusSmall), onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( color: selected ? AppTokens.primary.withValues(alpha: 0.10) : AppTokens.surface, borderRadius: BorderRadius.circular(AppTokens.radiusSmall), border: Border.all( color: selected ? AppTokens.primary : AppTokens.border, ), ), child: Center( child: Text( label, style: Theme.of(context).textTheme.labelLarge?.copyWith( color: selected ? AppTokens.primary : AppTokens.secondary, fontWeight: selected ? FontWeight.w700 : FontWeight.w500, ), ), ), ), ), ); } } class _StatCard extends StatelessWidget { const _StatCard({ required this.label, required this.value, required this.color, required this.icon, }); final String label; final String value; final Color color; final IconData icon; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: color.withValues(alpha: 0.10), borderRadius: BorderRadius.circular(AppTokens.radiusMedium), border: Border.all(color: color.withValues(alpha: 0.20)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, color: color, size: 20), const SizedBox(height: 6), Text( value, style: Theme.of(context).textTheme.headlineSmall?.copyWith( color: color, fontWeight: FontWeight.w800, ), ), Text( label, style: Theme.of(context).textTheme.bodySmall?.copyWith( color: AppTokens.secondary, ), ), ], ), ); } } class _StockRow extends StatelessWidget { const _StockRow({required this.item}); final Map item; @override Widget build(BuildContext context) { final stock = double.tryParse('${item['stock'] ?? 0}') ?? 0; final stockMin = double.tryParse('${item['stock_min'] ?? 0}') ?? 0; final color = stock <= 0 ? AppTokens.danger : AppTokens.warning; return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ Container( width: 8, height: 36, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(4), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item['description']?.toString() ?? '-', maxLines: 1, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.titleSmall, ), const SizedBox(height: 2), Text( 'Mín: ${stockMin.toStringAsFixed(0)}', style: Theme.of(context).textTheme.labelSmall?.copyWith( color: AppTokens.secondary, ), ), ], ), ), Text( '${stock.toStringAsFixed(0)} u', style: Theme.of(context).textTheme.titleSmall?.copyWith( color: color, fontWeight: FontWeight.w700, ), ), ], ), ); } }