import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:farolero/l10n/generated/app_localizations.dart'; import '../modelos/usuario.dart'; import '../servicios/servicio_nearby.dart'; import '../tema/tema_app.dart'; /// Lobby del host. El host es autoridad de sala y también cliente local. class PantallaLobbyHost extends StatefulWidget { final String nombreSala; final VoidCallback onIniciar; const PantallaLobbyHost({ super.key, required this.nombreSala, required this.onIniciar, }); @override State createState() => _PantallaLobbyHostState(); } class _PantallaLobbyHostState extends State { bool _iniciando = false; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final nearby = context.watch(); final sala = nearby.estadoSala; final usuarios = nearby.usuarios; final seleccionados = usuarios.where((u) => u.estaSeleccionado).length; final validacionInicio = sala?.validarInicio(); final puedeIniciar = validacionInicio?.exitoso ?? false; return Scaffold( appBar: AppBar( title: Text(widget.nombreSala), leading: IconButton( icon: const Icon(Icons.close), onPressed: () async { await nearby.desconectar(); if (context.mounted) Navigator.pop(context); }, ), ), body: Padding( padding: const EdgeInsets.all(24), child: Column( children: [ Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), ), child: QrImageView( data: nearby.generarDatosQR(widget.nombreSala), version: QrVersions.auto, size: 160, backgroundColor: Colors.white, ), ), const SizedBox(height: 12), Text(l10n.scanToJoin), const SizedBox(height: 16), _buildResumenSala(context, seleccionados, nearby.jugadores.length), const SizedBox(height: 12), Expanded( child: Card( child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( 'Usuarios de la partida', style: Theme.of(context).textTheme.titleLarge, ), ), IconButton.filledTonal( onPressed: () => _crearNuevoUsuario(context), icon: const Icon(Icons.person_add), ), ], ), const SizedBox(height: 8), Expanded( child: usuarios.isEmpty ? Center(child: Text(l10n.waitingForPlayers)) : ListView.builder( itemCount: usuarios.length, itemBuilder: (context, index) => _buildUsuarioTile(context, usuarios[index]), ), ), ], ), ), ), ), const SizedBox(height: 12), if (!puedeIniciar) Text( _mensajeValidacion(validacionInicio?.codigo), style: Theme.of(context) .textTheme .bodyMedium ?.copyWith(color: TemaApp.colorNaranja), textAlign: TextAlign.center, ), const SizedBox(height: 12), SizedBox( width: double.infinity, child: ElevatedButton.icon( onPressed: puedeIniciar && !_iniciando ? () { setState(() => _iniciando = true); widget.onIniciar(); } : null, icon: const Icon(Icons.play_arrow), label: Text(_iniciando ? l10n.starting : l10n.startGame), ), ), ], ), ), ); } Widget _buildResumenSala( BuildContext context, int seleccionados, int clientesRemotos, ) { return Row( children: [ Expanded( child: _buildStat( context, icon: Icons.groups, label: 'Jugadores seleccionados', value: '$seleccionados', ok: seleccionados >= 3, ), ), const SizedBox(width: 8), Expanded( child: _buildStat( context, icon: Icons.devices, label: 'Móviles conectados', value: '${clientesRemotos + 1}', ok: true, ), ), ], ); } Widget _buildStat( BuildContext context, { required IconData icon, required String label, required String value, required bool ok, }) { final color = ok ? TemaApp.colorVerde : TemaApp.colorNaranja; return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: color.withValues(alpha: 0.18), borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Icon(icon, color: color), const SizedBox(width: 8), Expanded( child: Text(label, style: Theme.of(context).textTheme.bodySmall), ), Text( value, style: TextStyle(color: color, fontWeight: FontWeight.bold), ), ], ), ); } Widget _buildUsuarioTile(BuildContext context, Usuario usuario) { final nearby = context.read(); final miClientId = nearby.miClientId; final seleccionadoPorMi = usuario.clienteIdSeleccionado == miClientId; final seleccionadoPorOtro = usuario.estaSeleccionado && usuario.clienteIdSeleccionado != miClientId; return ListTile( leading: CircleAvatar( backgroundColor: seleccionadoPorMi ? TemaApp.colorVerde : seleccionadoPorOtro ? TemaApp.colorNaranja : TemaApp.colorTarjeta, child: Text(usuario.avatar ?? '👤'), ), title: Text(usuario.nombre), subtitle: Text( seleccionadoPorMi ? 'Seleccionado por este móvil' : seleccionadoPorOtro ? 'Seleccionado por otro cliente' : 'Disponible', ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (seleccionadoPorMi) IconButton( tooltip: 'Liberar', icon: const Icon(Icons.close), onPressed: () => nearby.liberarUsuarioSala(usuario.id), ) else if (!seleccionadoPorOtro) IconButton( tooltip: 'Seleccionar', icon: const Icon(Icons.check_circle_outline), onPressed: () => nearby.seleccionarUsuarioSala(usuario.id), ), if (!usuario.estaSeleccionado) IconButton( tooltip: 'Eliminar', icon: const Icon(Icons.delete_outline, color: TemaApp.colorAcento), onPressed: () => nearby.eliminarUsuarioSala(usuario.id), ), ], ), ); } String _mensajeValidacion(String? codigo) { switch (codigo) { case 'faltan_jugadores': return 'Seleccioná al menos 3 usuarios para iniciar.'; case 'host_sin_usuario': return 'El móvil servidor debe seleccionar al menos un usuario.'; case 'sala_cerrada': return 'La sala ya no está en lobby.'; default: return 'Completá la selección de usuarios para iniciar.'; } } Future _crearNuevoUsuario(BuildContext context) async { final l10n = AppLocalizations.of(context)!; final controller = TextEditingController(); final nearby = context.read(); final nombre = await showDialog( context: context, builder: (ctx) => AlertDialog( title: Text(l10n.createNewUser), content: TextField( controller: controller, autofocus: true, textCapitalization: TextCapitalization.words, decoration: InputDecoration( hintText: l10n.yourName, prefixIcon: const Icon(Icons.person), ), onSubmitted: (v) => Navigator.pop(ctx, v), ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: Text(l10n.cancel), ), TextButton( onPressed: () => Navigator.pop(ctx, controller.text), child: Text(l10n.accept), ), ], ), ); if (nombre != null && nombre.trim().isNotEmpty) { await nearby.crearUsuarioSala(nombre.trim(), seleccionar: true); } } }