import 'dart:async'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../core/app_colors.dart'; import '../../database/db_helper.dart'; import '../../services/auth_service.dart'; class ReporteChatScreen extends StatefulWidget { final int reporteId; final String folio; final bool isClosed; const ReporteChatScreen({super.key, required this.reporteId, required this.folio, this.isClosed = false}); @override State createState() => _ReporteChatScreenState(); } class _ReporteChatScreenState extends State { final _ctrl = TextEditingController(); final _scroll = ScrollController(); List> _msgs = []; bool _loading = true; Timer? _timer; @override void initState() { super.initState(); _load(); _timer = Timer.periodic(const Duration(seconds: 5), (_) => _load()); } Future _load() async { final auth = context.read(); final rol = auth.currentUser?.rol ?? 'CIUDADANO'; final msgs = await DbHelper.getChatMsgs(widget.reporteId); await DbHelper.markChatRead(widget.reporteId, rol); if (mounted) { setState(() { _msgs = msgs; _loading = false; }); WidgetsBinding.instance.addPostFrameCallback((_) { if (_scroll.hasClients) _scroll.animateTo(_scroll.position.maxScrollExtent, duration: const Duration(milliseconds: 200), curve: Curves.easeOut); }); } } Future _send() async { final text = _ctrl.text.trim(); if (text.isEmpty) return; final auth = context.read(); final user = auth.currentUser; if (user == null) return; _ctrl.clear(); await DbHelper.insertChatMsg(widget.reporteId, user.id!, user.rol, text); await _load(); } @override Widget build(BuildContext context) { final auth = context.watch(); final myRol = auth.currentUser?.rol ?? 'CIUDADANO'; final isAdmin = myRol == 'ADMINISTRADOR'; final accent = isAdmin ? AppColors.verdeAdmin : AppColors.guindaPrimary; return Scaffold( backgroundColor: AppColors.grisFondo, appBar: AppBar( backgroundColor: accent, foregroundColor: Colors.white, title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Chat del Reporte', style: TextStyle(fontSize: 15, fontWeight: FontWeight.bold)), Text('Folio: ${widget.folio}', style: const TextStyle(fontSize: 11, color: Colors.white70)), ]), bottom: PreferredSize(preferredSize: const Size.fromHeight(4), child: Container(height: 4, color: AppColors.dorado)), actions: [if (widget.isClosed) Container(margin: const EdgeInsets.only(right: 12), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration(color: AppColors.verdeExito, borderRadius: BorderRadius.circular(12)), child: const Text('COMPLETADO', style: TextStyle(fontSize: 10, color: Colors.white, fontWeight: FontWeight.bold)))], ), body: Column(children: [ if (widget.isClosed) Container( width: double.infinity, padding: const EdgeInsets.all(10), color: AppColors.verdeExito.withOpacity(0.08), child: const Row(mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.lock, size: 14, color: AppColors.verdeExito), SizedBox(width: 6), Text('Reporte completado. Chat cerrado.', style: TextStyle(fontSize: 12, color: AppColors.verdeExito, fontWeight: FontWeight.w600)), ])), Expanded(child: _loading ? const Center(child: CircularProgressIndicator()) : _msgs.isEmpty ? Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.chat_bubble_outline, size: 48, color: Colors.grey.shade400), const SizedBox(height: 12), Text(isAdmin ? 'Inicia la conversacion con el ciudadano' : 'Escribe tu mensaje al Ayuntamiento', style: TextStyle(color: Colors.grey.shade500)), ])) : ListView.builder( controller: _scroll, padding: const EdgeInsets.all(12), itemCount: _msgs.length, itemBuilder: (_, i) { final m = _msgs[i]; final rol = m['rol'] as String; final isMe = rol == myRol; final fecha = DateTime.tryParse(m['fecha'] as String? ?? ''); final hora = fecha != null ? '${fecha.hour.toString().padLeft(2,'0')}:${fecha.minute.toString().padLeft(2,'0')}' : ''; return Padding( padding: const EdgeInsets.symmetric(vertical: 3), child: Row( mainAxisAlignment: isMe ? MainAxisAlignment.end : MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [ if (!isMe) ...[ CircleAvatar(radius: 14, backgroundColor: (rol=='ADMINISTRADOR' ? AppColors.verdeAdmin : AppColors.guindaPrimary).withOpacity(0.15), child: Icon(rol=='ADMINISTRADOR' ? Icons.admin_panel_settings : Icons.person, size: 14, color: rol=='ADMINISTRADOR' ? AppColors.verdeAdmin : AppColors.guindaPrimary)), const SizedBox(width: 6), ], Flexible(child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: isMe ? accent : Colors.white, borderRadius: BorderRadius.only( topLeft: const Radius.circular(16), topRight: const Radius.circular(16), bottomLeft: Radius.circular(isMe ? 16 : 4), bottomRight: Radius.circular(isMe ? 4 : 16), ), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.07), blurRadius: 4)], ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ if (!isMe) Text(rol=='ADMINISTRADOR' ? 'Ayuntamiento' : 'Ciudadano', style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: rol=='ADMINISTRADOR' ? AppColors.verdeAdmin : AppColors.guindaPrimary)), Text(m['mensaje'] as String? ?? '', style: TextStyle(fontSize: 13, height: 1.4, color: isMe ? Colors.white : AppColors.negroTexto)), Text(hora, style: TextStyle(fontSize: 9, color: isMe ? Colors.white60 : AppColors.grisTexto)), ]), )), if (isMe) const SizedBox(width: 6), ], ), ); })), if (!widget.isClosed) Container( padding: const EdgeInsets.fromLTRB(12, 8, 12, 12), decoration: BoxDecoration(color: Colors.white, boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 4, offset: const Offset(0,-2))]), child: SafeArea(top: false, child: Row(children: [ Expanded(child: TextField( controller: _ctrl, maxLines: 3, minLines: 1, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration( hintText: isAdmin ? 'Responde al ciudadano...' : 'Escribe al Ayuntamiento...', border: OutlineInputBorder(borderRadius: BorderRadius.circular(24), borderSide: BorderSide.none), filled: true, fillColor: AppColors.grisFondo, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), isDense: true), )), const SizedBox(width: 8), CircleAvatar(radius: 22, backgroundColor: accent, child: IconButton(icon: const Icon(Icons.send, color: Colors.white, size: 18), onPressed: _send)), ]))) else Container(padding: const EdgeInsets.all(14), color: Colors.white, child: const Row(mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.lock_outline, size: 16, color: AppColors.grisTexto), SizedBox(width: 6), Text('Chat cerrado', style: TextStyle(color: AppColors.grisTexto, fontSize: 12)), ])), ]), ); } @override void dispose() { _ctrl.dispose(); _scroll.dispose(); _timer?.cancel(); super.dispose(); } }