import 'package:enter_farma_plus_mobile/src/app/widgets/app_panel.dart'; import 'package:enter_farma_plus_mobile/src/app/widgets/empty_state_panel.dart'; import 'package:enter_farma_plus_mobile/src/core/network/api_client.dart'; import 'package:enter_farma_plus_mobile/src/core/theme/app_tokens.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class QuickSummaryScreen extends ConsumerStatefulWidget { const QuickSummaryScreen({super.key}); @override ConsumerState createState() => _QuickSummaryScreenState(); } class _QuickSummaryScreenState extends ConsumerState { final _numberController = TextEditingController(); bool _isSearching = false; bool _isLoadingTables = true; Map? _result; String? _error; List> _docTypes = const []; List> _allSeries = const []; String? _docTypeId; int? _seriesId; @override void initState() { super.initState(); _loadTables(); } @override void dispose() { _numberController.dispose(); super.dispose(); } Future _loadTables() async { final response = await ref.read(apiClientProvider).documentsTables(); if (!mounted) return; final data = response.data ?? const {}; final saleDetail = Map.from(data['sale_detail'] as Map? ?? const {}); final salePayment = Map.from(data['sale_payment'] as Map? ?? const {}); final docTypes = List>.from( saleDetail['document_types'] as List? ?? const []); // Solo electrónicos: Factura (01) y Boleta (03). final filtered = docTypes.where((t) => ['01', '03'].contains(t['id']?.toString())).toList(); final series = List>.from( salePayment['series'] as List? ?? const []); setState(() { _isLoadingTables = false; _docTypes = filtered; _allSeries = series; if (filtered.isNotEmpty) { _docTypeId = filtered.first['id']?.toString(); final firstSeries = _seriesForDocType(_docTypeId); _seriesId = firstSeries.isNotEmpty ? int.tryParse('${firstSeries.first['id']}') : null; } }); } List> _seriesForDocType(String? docTypeId) { if (docTypeId == null) return const []; return _allSeries .where((s) => '${s['document_type_id']}' == docTypeId) .toList(); } String _shortDocLabel(String? id) { switch (id) { case '01': return 'Factura'; case '03': return 'Boleta'; default: return 'Documento'; } } Future _search() async { final number = _numberController.text.trim(); if (_seriesId == null) { setState(() => _error = 'Selecciona una serie.'); return; } if (number.isEmpty) { setState(() => _error = 'Ingresa el número.'); return; } final seriesRow = _allSeries.firstWhere( (s) => '${s['id']}' == '$_seriesId', orElse: () => const {}, ); final series = seriesRow['number']?.toString() ?? ''; if (series.isEmpty) { setState(() => _error = 'Serie inválida.'); return; } if (series.isEmpty || number.isEmpty) { setState(() => _error = 'Ingresa serie y número.'); return; } setState(() { _isSearching = true; _error = null; _result = null; }); // Busca por número (string), luego filtra por serie exacta. final response = await ref.read(apiClientProvider).documents( model: 'document', search: number, perPage: 50, ); if (!mounted) return; if (!response.success) { setState(() { _isSearching = false; _error = response.message ?? 'No se pudo buscar.'; }); return; } final list = response.data ?? const >[]; Map? match; for (final r in list) { if ('${r['series']}' == series && '${r['number']}' == number) { match = r; break; } } setState(() { _isSearching = false; _result = match; if (match == null) { _error = 'No se encontró el comprobante $series-$number.'; } }); } Future _consultSunat() async { if (_result == null) return; final id = int.tryParse('${_result!['id']}') ?? 0; if (id <= 0) return; setState(() => _isSearching = true); // ignore: avoid_print print('[EnterFarma] consultando SUNAT id=$id'); // Reusa el endpoint existente vía la API client si existe; si no, llama directo. final api = ref.read(apiClientProvider); final response = await api.sendDocumentToSunat(id: id); if (!mounted) return; setState(() => _isSearching = false); if (response.success) { final updated = (response.data?['record'] is Map) ? Map.from(response.data!['record'] as Map) : null; if (updated != null) { setState(() => _result = updated); } ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(response.message ?? 'Consulta realizada.'), backgroundColor: AppTokens.success, ), ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(response.message ?? 'No se pudo consultar.'), backgroundColor: AppTokens.danger, ), ); } } Color _stateColor(String stateId) { switch (stateId) { case '05': return AppTokens.success; case '11': case '13': return AppTokens.danger; case '09': return AppTokens.danger; case '01': case '03': return AppTokens.warning; default: return AppTokens.secondary; } } IconData _stateIcon(String stateId) { switch (stateId) { case '05': return Icons.check_circle_rounded; case '11': case '13': return Icons.cancel_rounded; case '09': return Icons.error_rounded; case '01': case '03': return Icons.hourglass_top_rounded; default: return Icons.help_rounded; } } @override Widget build(BuildContext context) { return SafeArea( child: ListView( padding: AppTokens.pagePadding, children: [ AppPanel( title: 'Consultar comprobante en SUNAT', child: _isLoadingTables ? const Padding( padding: EdgeInsets.symmetric(vertical: 24), child: Center(child: CircularProgressIndicator()), ) : Column( children: [ // Selector de tipo de comprobante (chips) Wrap( spacing: 8, runSpacing: 8, children: [ for (final dt in _docTypes) ChoiceChip( label: Text(_shortDocLabel(dt['id']?.toString())), selected: _docTypeId == dt['id']?.toString(), onSelected: (_) { setState(() { _docTypeId = dt['id']?.toString(); final s = _seriesForDocType(_docTypeId); _seriesId = s.isNotEmpty ? int.tryParse('${s.first['id']}') : null; }); }, ), ], ), const SizedBox(height: 14), // Serie + Número Row( children: [ SizedBox( width: 110, child: DropdownButtonFormField( initialValue: _seriesId, isExpanded: true, decoration: const InputDecoration( labelText: 'Serie', isDense: true, contentPadding: EdgeInsets.symmetric( horizontal: 10, vertical: 14), ), items: [ for (final s in _seriesForDocType(_docTypeId)) DropdownMenuItem( value: int.tryParse('${s['id']}'), child: Text( s['number']?.toString() ?? '-', maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], onChanged: (v) => setState(() => _seriesId = v), ), ), const SizedBox(width: 12), Expanded( child: TextField( controller: _numberController, keyboardType: TextInputType.number, decoration: const InputDecoration( labelText: 'Número', hintText: '123', prefixIcon: Icon(Icons.numbers_rounded), ), ), ), ], ), const SizedBox(height: 14), SizedBox( width: double.infinity, child: FilledButton.icon( onPressed: _isSearching ? null : _search, icon: _isSearching ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : const Icon(Icons.search_rounded), label: Text(_isSearching ? 'Buscando...' : 'Buscar'), ), ), ], ), ), if (_error != null) ...[ const SizedBox(height: 14), EmptyStatePanel( icon: Icons.info_outline_rounded, title: 'Sin resultado', subtitle: _error!, ), ], if (_result != null) ...[ const SizedBox(height: 14), _buildResultPanel(_result!), ], ], ), ); } Widget _buildResultPanel(Map doc) { final stateId = doc['state_type_id']?.toString() ?? ''; final stateLabel = doc['state_type_description']?.toString() ?? 'Desconocido'; final number = doc['number_full']?.toString() ?? '${doc['series'] ?? ''}-${doc['number'] ?? ''}'; final docDesc = doc['document_type_description']?.toString() ?? ''; final customer = doc['customer_name']?.toString() ?? doc['customer']?['name']?.toString() ?? '-'; final total = doc['total']?.toString() ?? '0.00'; final dateOfIssue = doc['date_of_issue']?.toString() ?? '-'; final color = _stateColor(stateId); final icon = _stateIcon(stateId); return AppPanel( title: number, subtitle: docDesc, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ 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.25)), ), child: Row( children: [ Icon(icon, color: color, size: 28), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Estado SUNAT', style: Theme.of(context).textTheme.labelSmall?.copyWith( color: AppTokens.secondary, ), ), const SizedBox(height: 2), Text( stateLabel, style: Theme.of(context).textTheme.titleMedium?.copyWith( color: color, fontWeight: FontWeight.w800, ), ), ], ), ), ], ), ), const SizedBox(height: 14), _Line(label: 'Fecha', value: dateOfIssue), const Divider(height: 22), _Line(label: 'Cliente', value: customer), const Divider(height: 22), _Line(label: 'Total', value: 'S/ $total'), const SizedBox(height: 16), if (stateId != '05') SizedBox( width: double.infinity, child: FilledButton.icon( style: FilledButton.styleFrom(backgroundColor: AppTokens.warning), onPressed: _isSearching ? null : _consultSunat, icon: const Icon(Icons.cloud_sync_rounded), label: const Text('Consultar / reenviar a SUNAT'), ), ), ], ), ); } } class _Line extends StatelessWidget { const _Line({required this.label, required this.value}); final String label; final String value; @override Widget build(BuildContext context) { return Row( children: [ Expanded( child: Text( label, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: AppTokens.secondary, ), ), ), Text( value, style: Theme.of(context).textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w700, ), ), ], ); } }