import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'dart:convert'; import '../models/allarme.dart'; import '../models/sito.dart'; import '../services/api_service.dart'; import '../utils/constants.dart'; class AllarmeDetailScreen extends StatefulWidget { final Allarme allarme; const AllarmeDetailScreen({super.key, required this.allarme}); @override State createState() => _AllarmeDetailScreenState(); } class _AllarmeDetailScreenState extends State { final _apiService = ApiService(); late Allarme _allarme; bool _isUpdating = false; bool _isLoadingSito = true; Sito? _sito; GoogleMapController? _mapController; @override void initState() { super.initState(); _allarme = widget.allarme; _loadSito(); } Future _loadSito() async { try { final sito = await _apiService.getSito(_allarme.sitoId); setState(() { _sito = sito; _isLoadingSito = false; }); } catch (e) { setState(() => _isLoadingSito = false); } } @override void dispose() { _mapController?.dispose(); super.dispose(); } Color _getSeverityColor() { switch (_allarme.severita) { case 'critical': return AppColors.critical; case 'warning': return AppColors.warning; case 'info': return AppColors.info; default: return AppColors.textSecondary; } } Future _updateStato(String nuovoStato) async { setState(() => _isUpdating = true); try { final updatedAllarme = await _apiService.updateAllarme( _allarme.id, stato: nuovoStato, ); setState(() { _allarme = updatedAllarme; _isUpdating = false; }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Stato aggiornato a: ${_allarme.statoReadable}'), backgroundColor: AppColors.success, ), ); } } catch (e) { setState(() => _isUpdating = false); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Errore aggiornamento: $e'), backgroundColor: AppColors.critical, ), ); } } } void _showStatoDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Cambia Stato'), content: Column( mainAxisSize: MainAxisSize.min, children: [ _buildStatoOption('nuovo', 'Nuovo', Icons.fiber_new), _buildStatoOption('in_gestione', 'In Gestione', Icons.engineering), _buildStatoOption('risolto', 'Risolto', Icons.check_circle), ], ), ), ); } Widget _buildStatoOption(String stato, String label, IconData icon) { final isCurrentStato = _allarme.stato == stato; return ListTile( leading: Icon( icon, color: isCurrentStato ? AppColors.primary : AppColors.textSecondary, ), title: Text( label, style: TextStyle( fontWeight: isCurrentStato ? FontWeight.bold : FontWeight.normal, color: isCurrentStato ? AppColors.primary : null, ), ), trailing: isCurrentStato ? const Icon(Icons.check, color: AppColors.primary) : null, onTap: isCurrentStato ? null : () { Navigator.pop(context); _updateStato(stato); }, ); } @override Widget build(BuildContext context) { final dateFormat = DateFormat('dd/MM/yyyy HH:mm'); return Scaffold( appBar: AppBar( title: const Text('Dettaglio Allarme'), actions: [ if (!_isUpdating) IconButton( icon: const Icon(Icons.edit), onPressed: _showStatoDialog, tooltip: 'Cambia stato', ), ], ), body: _isUpdating ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header con severità Container( width: double.infinity, padding: const EdgeInsets.all(AppSizes.paddingL), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ _getSeverityColor(), _getSeverityColor().withOpacity(0.7), ], ), ), child: SafeArea( bottom: false, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), ), child: Text( _allarme.severitaReadable, style: TextStyle( color: _getSeverityColor(), fontWeight: FontWeight.bold, fontSize: 14, ), ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6, ), decoration: BoxDecoration( color: Colors.white.withOpacity(0.9), borderRadius: BorderRadius.circular(20), ), child: Row( children: [ Icon( _getStatoIcon(), size: 16, color: _getStatoColor(), ), const SizedBox(width: 4), Text( _allarme.statoReadable, style: TextStyle( color: _getStatoColor(), fontWeight: FontWeight.bold, fontSize: 14, ), ), ], ), ), ], ), const SizedBox(height: 16), Text( _allarme.titolo, style: const TextStyle( color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Row( children: [ Icon( AlarmTypeIcons.getIcon(_allarme.tipo), color: Colors.white.withOpacity(0.9), size: 18, ), const SizedBox(width: 8), Text( _allarme.tipoReadable, style: TextStyle( color: Colors.white.withOpacity(0.9), fontSize: 16, ), ), ], ), ], ), ), ), // Informazioni principali Padding( padding: const EdgeInsets.all(AppSizes.paddingL), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Descrizione if (_allarme.descrizione != null) ...[ const Text( 'Descrizione', style: AppTextStyles.h3, ), const SizedBox(height: 8), Text( _allarme.descrizione!, style: AppTextStyles.bodyLarge, ), const SizedBox(height: 24), ], // Valori rilevati if (_allarme.valoreRilevato != null && _allarme.valoreSoglia != null) ...[ const Text( 'Valori Rilevati', style: AppTextStyles.h3, ), const SizedBox(height: 12), _buildInfoCard( icon: Icons.analytics, title: 'Valore Rilevato', value: '${_allarme.valoreRilevato!.toStringAsFixed(2)} ${_allarme.unitaMisura ?? ''}', color: _getSeverityColor(), ), const SizedBox(height: 8), _buildInfoCard( icon: Icons.straighten, title: 'Soglia Impostata', value: '${_allarme.valoreSoglia!.toStringAsFixed(2)} ${_allarme.unitaMisura ?? ''}', color: AppColors.textSecondary, ), const SizedBox(height: 24), ], // Dati sensori if (_allarme.datiSensori != null && _allarme.datiSensori!.isNotEmpty) ...[ const Text( 'Dati Sensori', style: AppTextStyles.h3, ), const SizedBox(height: 12), _buildSensorsData(), const SizedBox(height: 24), ], // Informazioni temporali const Text( 'Informazioni Temporali', style: AppTextStyles.h3, ), const SizedBox(height: 12), _buildInfoCard( icon: Icons.access_time, title: 'Rilevato il', value: dateFormat.format(_allarme.timestampRilevamento), ), const SizedBox(height: 8), _buildInfoCard( icon: Icons.schedule, title: 'Creato il', value: dateFormat.format(_allarme.createdAt), ), const SizedBox(height: 24), // Mappa con posizione sito if (_sito != null && _sito!.hasCoordinates) ...[ const Text( 'Posizione Sito', style: AppTextStyles.h3, ), const SizedBox(height: 12), _buildMapView(), const SizedBox(height: 8), _buildInfoCard( icon: Icons.place, title: 'Sito', value: '${_sito!.nome} - ${_sito!.localita}', ), const SizedBox(height: 24), ] else if (_isLoadingSito) ...[ const Center( child: Padding( padding: EdgeInsets.all(20.0), child: CircularProgressIndicator(), ), ), const SizedBox(height: 24), ], // Dettagli tecnici const Text( 'Dettagli Tecnici', style: AppTextStyles.h3, ), const SizedBox(height: 12), _buildInfoCard( icon: Icons.tag, title: 'ID Allarme', value: '#${_allarme.id}', ), const SizedBox(height: 8), _buildInfoCard( icon: Icons.location_on, title: 'ID Sito', value: '#${_allarme.sitoId}', ), ], ), ), ], ), ), bottomNavigationBar: !_isUpdating && _allarme.stato != 'risolto' ? SafeArea( child: Padding( padding: const EdgeInsets.all(AppSizes.paddingL), child: ElevatedButton.icon( onPressed: () => _updateStato('risolto'), icon: const Icon(Icons.check_circle), label: const Text('Segna come Risolto'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.success, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 16), ), ), ), ) : null, ); } Widget _buildInfoCard({ required IconData icon, required String title, required String value, Color? color, }) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[300]!), ), child: Row( children: [ Icon(icon, color: color ?? AppColors.primary, size: 20), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: AppTextStyles.bodySmall.copyWith( color: AppColors.textSecondary, ), ), const SizedBox(height: 2), Text( value, style: AppTextStyles.bodyMedium.copyWith( fontWeight: FontWeight.w600, ), ), ], ), ), ], ), ); } Widget _buildSensorsData() { final jsonEncoder = const JsonEncoder.withIndent(' '); final prettyJson = jsonEncoder.convert(_allarme.datiSensori); return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey[900], borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon( Icons.sensors, color: Colors.greenAccent, size: 20, ), const SizedBox(width: 8), const Text( 'JSON Data', style: TextStyle( color: Colors.greenAccent, fontWeight: FontWeight.bold, ), ), ], ), const SizedBox(height: 12), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Text( prettyJson, style: const TextStyle( fontFamily: 'monospace', color: Colors.white, fontSize: 12, ), ), ), ], ), ); } IconData _getStatoIcon() { switch (_allarme.stato) { case 'nuovo': return Icons.fiber_new; case 'in_gestione': return Icons.engineering; case 'risolto': return Icons.check_circle; default: return Icons.info; } } Color _getStatoColor() { switch (_allarme.stato) { case 'nuovo': return AppColors.critical; case 'in_gestione': return AppColors.warning; case 'risolto': return AppColors.success; default: return AppColors.textSecondary; } } Widget _buildMapView() { if (_sito == null || !_sito!.hasCoordinates) { return const SizedBox.shrink(); } final position = LatLng(_sito!.latitudine!, _sito!.longitudine!); return Container( height: 200, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey[300]!), ), clipBehavior: Clip.hardEdge, child: GoogleMap( initialCameraPosition: CameraPosition( target: position, zoom: 15, ), markers: { Marker( markerId: MarkerId('sito_${_sito!.id}'), position: position, infoWindow: InfoWindow( title: _sito!.nome, snippet: _sito!.tipoReadable, ), icon: BitmapDescriptor.defaultMarkerWithHue( _getSeverityColor() == AppColors.critical ? BitmapDescriptor.hueRed : _getSeverityColor() == AppColors.warning ? BitmapDescriptor.hueOrange : BitmapDescriptor.hueBlue, ), ), }, myLocationButtonEnabled: false, zoomControlsEnabled: true, mapToolbarEnabled: false, onMapCreated: (controller) { _mapController = controller; }, ), ); } }