import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:provider/provider.dart';
import 'package:farolero/l10n/generated/app_localizations.dart';
import '../modelos/jugador.dart';
import '../modelos/inicio_partida_multijugador.dart';
import '../modelos/snapshot_partida_online.dart';
import '../modelos/usuario.dart';
import '../servicios/servicio_nearby.dart';
import '../servicios/servicio_permisos.dart';
import '../servicios/servicio_perfil_usuario.dart';
import '../tema/componentes_farolero.dart';
import '../tema/tema_app.dart';
import 'pantalla_palabra_cliente.dart';
import 'pantalla_palabras_cliente.dart';
import 'pantalla_debate_cliente.dart';
import 'pantalla_votacion_cliente.dart';
import 'pantalla_resultado_online.dart';
import 'pantalla_fin_partida_online.dart';

/// Pantalla para unirse a una partida multidispositivo.
/// Flujo: nombre → discovery automático (lista de salas) → fallback QR
class PantallaUnirse extends StatefulWidget {
  const PantallaUnirse({super.key});

  @override
  State<PantallaUnirse> createState() => _PantallaUnirseState();
}

class _PantallaUnirseState extends State<PantallaUnirse> {
  final _nombreController = TextEditingController();
  final _formKey = GlobalKey<FormState>();

  // Estados de la pantalla
  bool _buscando = false;
  bool _escaneandoQR = false;
  bool _conectando = false;
  String? _error;
  String? _salaSeleccionada;

  // Estado del juego recibido del host
  String? _palabraRecibida;
  bool _esImpostor = false;
  String? _pistaCategoria;
  String? _partidaId;
  final List<Jugador> _jugadores = [];
  final List<JugadorInicioPartida> _jugadoresControlados = [];

  @override
  void initState() {
    super.initState();
    // Registrar listener ANTES del primer build
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final perfil = context.read<ServicioPerfilUsuario>().perfil;
      if (_nombreController.text.isEmpty) {
        _nombreController.text = perfil.nombre;
      }
      _registrarListenerPartida();
    });
  }

  void _registrarListenerPartida() {
    final nearby = context.read<ServicioNearby>();
    nearby.onMensaje((endpointId, mensaje) {
      if (!mounted) return;
      if (mensaje.tipo == TipoMensaje.partidaInicio) {
        // El host ha iniciado la partida — nos ha enviado nuestra palabra
        final jugadoresData = mensaje.datos['jugadores'] as List<dynamic>?;
        final jugadoresTodosData =
            mensaje.datos['jugadoresTodos'] as List<dynamic>?;
        setState(() {
          _jugadoresControlados
            ..clear()
            ..addAll(
              (jugadoresData ?? []).map(
                (json) => JugadorInicioPartida.fromJson(
                  json as Map<String, dynamic>,
                ),
              ),
            );
          _jugadores
            ..clear()
            ..addAll(
              (jugadoresTodosData ?? []).map(
                (json) => Jugador.fromJson(json as Map<String, dynamic>),
              ),
            );
          if (_jugadoresControlados.isNotEmpty) {
            final primero = _jugadoresControlados.first;
            _palabraRecibida = primero.palabra;
            _esImpostor = primero.esImpostor;
          } else {
            _palabraRecibida = mensaje.datos['palabra'] as String?;
            _esImpostor = mensaje.datos['esImpostor'] as bool? ?? false;
            if (_palabraRecibida != null) {
              _jugadoresControlados.add(
                JugadorInicioPartida(
                  jugadorId: nearby.miClientId ?? '_legacy',
                  nombre: _nombreController.text.trim().isEmpty
                      ? 'Jugador'
                      : _nombreController.text.trim(),
                  esImpostor: _esImpostor,
                  palabra: _palabraRecibida,
                ),
              );
            }
          }
          _pistaCategoria = mensaje.datos['categoria'] as String?;
          _partidaId = (mensaje.datos['roomId'] as String?) ??
              nearby.roomId ??
              (mensaje.datos['clientId'] as String?) ??
              DateTime.now().microsecondsSinceEpoch.toString();
        });
        // Navegar a pantalla de palabra del cliente
        if (mounted && (_jugadoresControlados.isNotEmpty || _palabraRecibida != null)) {
          _navegarAPalabra();
        }
      } else if (mensaje.tipo == TipoMensaje.fase) {
        final fase = mensaje.datos['fase'] as String?;
        _actualizarSnapshotSiExiste(mensaje.datos);
        if (mounted && fase != null) {
          _navegarSegunFase(fase, mensaje.datos);
        }
      } else if (mensaje.tipo == TipoMensaje.votacionResultado) {
        _actualizarSnapshotSiExiste(mensaje.datos);
        if (mounted) _navegarResultado(mensaje.datos);
      } else if (mensaje.tipo == TipoMensaje.partidaFin) {
        _actualizarSnapshotSiExiste(mensaje.datos);
        if (mounted) _navegarFinPartida(mensaje.datos);
      }
    });
  }

  void _navegarAPalabra() {
    if (_jugadoresControlados.isNotEmpty) {
      Navigator.of(context).push(
        MaterialPageRoute(
          builder: (_) => PantallaPalabrasCliente(
            jugadores: List.unmodifiable(_jugadoresControlados),
            pistaCategoria: _pistaCategoria,
            onTodosVistos: () {
              final nearby = context.read<ServicioNearby>();
              if (nearby.hostEndpointId != null) {
                nearby.enviarMensaje(
                  nearby.hostEndpointId!,
                  MensajeP2P(tipo: TipoMensaje.listo, datos: {}),
                );
              }
              Navigator.of(context).pop();
            },
          ),
        ),
      );
      return;
    }

    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (_) => PantallaPalabraCliente(
          palabra: _palabraRecibida ?? '',
          esImpostor: _esImpostor,
          pistaCategoria: _pistaCategoria,
          onVisto: () {
            // Enviar "listo" al host y volver a la espera
            final nearby = context.read<ServicioNearby>();
            if (nearby.hostEndpointId != null) {
              nearby.enviarMensaje(
                nearby.hostEndpointId!,
                MensajeP2P(tipo: TipoMensaje.listo, datos: {}),
              );
            }
            Navigator.of(context).pop();
          },
        ),
      ),
    );
  }

  void _actualizarSnapshotSiExiste(Map<String, dynamic> datos) {
    final jugadoresTodosData = datos['jugadoresTodos'] as List<dynamic>?;
    if (jugadoresTodosData == null) return;
    setState(() {
      _jugadores
        ..clear()
        ..addAll(
          jugadoresTodosData.map(
            (json) => Jugador.fromJson(json as Map<String, dynamic>),
          ),
        );
      _partidaId = (datos['roomId'] as String?) ??
          _partidaId ??
          context.read<ServicioNearby>().roomId;
      _pistaCategoria = (datos['categoria'] as String?) ?? _pistaCategoria;
    });
  }

  void _navegarSegunFase(String fase, [Map<String, dynamic>? datos]) {
    switch (fase) {
      case 'debate':
        final datosFase = datos ?? context.read<ServicioNearby>().datosPartida;
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(
            builder: (_) => PantallaDebateCliente(
              tiempoDebateSegundos:
                  datosFase?['tiempoDebateSegundos'] as int?,
              primerTurnoNombre:
                  datosFase?['primerTurnoNombre'] as String?,
              partidaId: _partidaId ?? context.read<ServicioNearby>().roomId,
              pistaCategoria: _pistaCategoria,
              jugadores: List.unmodifiable(_jugadores),
              jugadoresControlados: List.unmodifiable(_jugadoresControlados),
              onSolicitarVotacion: () {
                final nearby = context.read<ServicioNearby>();
                if (nearby.hostEndpointId != null) {
                  nearby.enviarMensaje(
                    nearby.hostEndpointId!,
                    MensajeP2P(
                      tipo: TipoMensaje.ping,
                      datos: {'solicitoVotacion': true},
                    ),
                  );
                }
              },
            ),
          ),
        );
        break;
      case 'votacion':
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(
            builder: (_) => PantallaVotacionCliente(
              jugadores: _jugadores,
              jugadoresControlados: List.unmodifiable(_jugadoresControlados),
              partidaId: _partidaId ?? context.read<ServicioNearby>().roomId,
              pistaCategoria: _pistaCategoria,
              onVotos: (votos) {
                final nearby = context.read<ServicioNearby>();
                if (nearby.hostEndpointId != null) {
                  for (final entry in votos.entries) {
                    nearby.enviarMensaje(
                      nearby.hostEndpointId!,
                      MensajeP2P(
                        tipo: TipoMensaje.voto,
                        datos: {
                          'votanteId': entry.key,
                          'votadoId': entry.value,
                          'votoporId': entry.value,
                        },
                      ),
                    );
                  }
                }
              },
            ),
          ),
        );
        break;
      case 'resultado':
      case 'adivinanza':
        _navegarResultado(datos ?? context.read<ServicioNearby>().datosPartida);
        break;
      case 'finPartida':
        _navegarFinPartida(datos ?? context.read<ServicioNearby>().datosPartida);
        break;
    }
  }

  void _navegarResultado(Map<String, dynamic>? datos) {
    if (datos == null) return;
    final snapshot = SnapshotPartidaOnline.fromJson(datos);
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) => PantallaResultadoOnline(
          snapshot: snapshot,
          jugadoresControlados: List.unmodifiable(_jugadoresControlados),
          pistaCategoria: _pistaCategoria,
        ),
      ),
    );
  }

  void _navegarFinPartida(Map<String, dynamic>? datos) {
    if (datos == null) return;
    final snapshot = SnapshotPartidaOnline.fromJson(datos);
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        builder: (_) => PantallaFinPartidaOnline(
          snapshot: snapshot,
          jugadoresControlados: List.unmodifiable(_jugadoresControlados),
          pistaCategoria: _pistaCategoria,
        ),
      ),
    );
  }
  @override
  void dispose() {
    _nombreController.dispose();
    super.dispose();
  }

  /// Paso 1: validar nombre, pedir permisos e iniciar discovery
  Future<void> _iniciarBusqueda() async {
    if (!_formKey.currentState!.validate()) return;

    // Solicitar permisos automáticamente
    final permisosOk = await ServicioPermisos.solicitarPermisosNearby(context);
    if (!permisosOk) {
      setState(() {
        _error =
            'Se necesitan permisos de Bluetooth y ubicación para buscar partidas.';
      });
      return;
    }

    if (!mounted) return;
    final nearby = context.read<ServicioNearby>();
    final servicioPerfil = context.read<ServicioPerfilUsuario>();
    final perfil = servicioPerfil.perfil;
    final gamificacion = servicioPerfil.resumenGamificacion;
    final ok = await nearby.buscarHosts(
      _nombreController.text.trim(),
      miNick: perfil.nick,
      miAvatar: perfil.avatarAsset,
      miFuego: gamificacion.fuego,
      miMedallas: gamificacion.medallas,
    );

    if (ok) {
      setState(() {
        _buscando = true;
        _error = null;
      });
    } else {
      setState(() {
        _error =
            'No se pudo iniciar la búsqueda. Verifica Bluetooth y ubicación.';
      });
    }
  }

  /// Conectar a un host de la lista
  Future<void> _conectarAHost(String endpointId, String nombreHost) async {
    setState(() {
      _conectando = true;
      _salaSeleccionada = nombreHost;
    });

    final nearby = context.read<ServicioNearby>();
    final servicioPerfil = context.read<ServicioPerfilUsuario>();
    final perfil = servicioPerfil.perfil;
    final gamificacion = servicioPerfil.resumenGamificacion;
    // Parar discovery antes de conectar
    await nearby.pararBusqueda();
    final ok = await nearby.conectarAHost(
      endpointId,
      _nombreController.text.trim(),
      miNick: perfil.nick,
      miAvatar: perfil.avatarAsset,
      miFuego: gamificacion.fuego,
      miMedallas: gamificacion.medallas,
    );

    if (!ok && mounted) {
      setState(() {
        _conectando = false;
        _error = 'No se pudo conectar a $nombreHost';
      });
      // Reiniciar búsqueda
      _iniciarBusqueda();
    }
  }

  /// Fallback: escanear QR
  void _abrirEscaner() {
    setState(() {
      _escaneandoQR = true;
      _error = null;
    });
  }

  Future<void> _onQRDetectado(BarcodeCapture capture) async {
    if (_conectando) return;

    for (final barcode in capture.barcodes) {
      final valor = barcode.rawValue;
      if (valor == null) continue;

      final datos = ServicioNearby.parsearQR(valor);
      if (datos != null) {
        setState(() {
          _escaneandoQR = false;
          _conectando = true;
          _salaSeleccionada =
              datos['host'] as String? ?? datos['sala'] as String? ?? 'Sala';
        });

        // Iniciar búsqueda para que Nearby encuentre al host
        final nearby = context.read<ServicioNearby>();
        if (!nearby.buscando) {
          final servicioPerfil = context.read<ServicioPerfilUsuario>();
          final perfil = servicioPerfil.perfil;
          final gamificacion = servicioPerfil.resumenGamificacion;
          await nearby.buscarHosts(
            _nombreController.text.trim(),
            miNick: perfil.nick,
            miAvatar: perfil.avatarAsset,
            miFuego: gamificacion.fuego,
            miMedallas: gamificacion.medallas,
          );
        }
        return;
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;
    final nearby = context.watch<ServicioNearby>();

    // Si estamos conectados → pantalla de espera
    if (nearby.conectado && !nearby.esHost) {
      return _buildPantallaEspera(context, l10n);
    }

    // Si escaneando QR
    if (_escaneandoQR) {
      return _buildEscaner(context, l10n);
    }

    // Si buscando hosts o conectando
    if (_buscando || _conectando) {
      return _buildDiscovery(context, l10n, nearby);
    }

    // Formulario nombre
    return _buildFormularioNombre(context, l10n);
  }

  // ==================== PASO 1: NOMBRE ====================

  Widget _buildFormularioNombre(BuildContext context, AppLocalizations l10n) {
    return Scaffold(
      appBar: AppBar(title: Text(l10n.joinGameTitle)),
      body: FondoFarolero(
        intenso: true,
        child: Padding(
          padding: const EdgeInsets.all(32),
          child: Form(
            key: _formKey,
            child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              EncabezadoFarolero(
                icono: Icons.bluetooth_searching,
                titulo: l10n.joinGameTitle,
                subtitulo: l10n.enterNameToSearch,
                color: TemaApp.colorAzul,
              ),
              const SizedBox(height: 32),
              TextFormField(
                controller: _nombreController,
                decoration: InputDecoration(
                  labelText: l10n.yourName,
                  prefixIcon: const Icon(Icons.person),
                ),
                validator: (v) {
                  if (v == null || v.trim().isEmpty) return l10n.nameRequired;
                  return null;
                },
                textCapitalization: TextCapitalization.words,
                onFieldSubmitted: (_) => _iniciarBusqueda(),
              ),
              const SizedBox(height: 24),
              BotonFarolero(
                texto: l10n.searchGames,
                icono: Icons.search,
                onPressed: _iniciarBusqueda,
              ),
              if (_error != null) ...[
                const SizedBox(height: 16),
                _buildError(_error!),
              ],
            ],
          ),
        ),
      ),
      ),
    );
  }

  // ==================== PASO 2: DISCOVERY ====================

  Widget _buildDiscovery(
    BuildContext context,
    AppLocalizations l10n,
    ServicioNearby nearby,
  ) {
    final hosts = nearby.hostsEncontrados;

    return Scaffold(
      appBar: AppBar(
        title: Text(l10n.joinGameTitle),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () async {
            await nearby.pararBusqueda();
            setState(() {
              _buscando = false;
              _conectando = false;
            });
          },
        ),
      ),
      body: FondoFarolero(
        intenso: true,
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            children: [
            EncabezadoFarolero(
              icono: _conectando ? Icons.sync : Icons.radar,
              titulo: _conectando
                  ? '${l10n.connectingTo} ${_salaSeleccionada ?? ""}...'
                  : l10n.searchingGames,
              subtitulo: _conectando
                  ? 'Preparando la sala segura'
                  : 'Buscando partidas cercanas por Bluetooth',
              color: _conectando ? TemaApp.colorAcento : TemaApp.colorNaranja,
              trailing: SizedBox(
                width: 24,
                height: 24,
                child: CircularProgressIndicator(
                  strokeWidth: 2.4,
                  color: _conectando
                      ? TemaApp.colorAcento
                      : TemaApp.colorNaranja,
                ),
              ),
            ),
            const SizedBox(height: 18),

            // Lista de hosts encontrados
            Expanded(
              child: hosts.isEmpty && !_conectando
                  ? Center(
                      child: EstadoVacioFarolero(
                        icono: Icons.radar,
                        titulo: l10n.noGamesFound,
                        subtitulo: l10n.noGamesFoundHint,
                      ),
                    )
                  : ListView.builder(
                      itemCount: hosts.length,
                      itemBuilder: (context, index) {
                        final entry = hosts.entries.elementAt(index);
                        return _buildHostTile(entry.key, entry.value);
                      },
                    ),
            ),

            if (_error != null) ...[
              _buildError(_error!),
              const SizedBox(height: 12),
            ],

            // Fallback: escanear QR
            if (!_conectando) ...[
              const Divider(),
              const SizedBox(height: 8),
              Text(
                l10n.orScanQR,
                style: Theme.of(
                  context,
                ).textTheme.bodyMedium?.copyWith(color: Colors.grey),
              ),
              const SizedBox(height: 8),
              SizedBox(
                width: double.infinity,
                child: OutlinedButton.icon(
                  onPressed: _abrirEscaner,
                  icon: const Icon(Icons.qr_code_scanner),
                  label: Text(l10n.scanQR),
                ),
              ),
            ],
          ],
        ),
      ),
      ),
    );
  }

  Widget _buildHostTile(String endpointId, String nombre) {
    return Container(
      margin: const EdgeInsets.only(bottom: 10),
      child: Material(
        color: Colors.transparent,
        borderRadius: BorderRadius.circular(18),
        child: InkWell(
          borderRadius: BorderRadius.circular(18),
          onTap: _conectando ? null : () => _conectarAHost(endpointId, nombre),
          child: Ink(
            decoration: TemaApp.decoracionPanel(
              color: TemaApp.colorTarjeta.withValues(alpha: 0.90),
              borderColor: TemaApp.colorNaranja.withValues(alpha: 0.42),
            ),
            child: Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
              child: Row(
                children: [
                  const Icon(
                    Icons.theater_comedy,
                    color: TemaApp.colorNaranja,
                    size: 30,
                  ),
                  const SizedBox(width: 16),
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          nombre,
                          style: Theme.of(context).textTheme.titleMedium,
                        ),
                        Text(
                          'Toca para unirte',
                          style: Theme.of(context).textTheme.bodySmall,
                        ),
                      ],
                    ),
                  ),
                  const Icon(
                    Icons.arrow_forward_ios,
                    size: 16,
                    color: TemaApp.colorDorado,
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  // ==================== ESCÁNER QR ====================

  Widget _buildEscaner(BuildContext context, AppLocalizations l10n) {
    return Scaffold(
      appBar: AppBar(
        title: Text(l10n.scanQR),
        leading: IconButton(
          icon: const Icon(Icons.arrow_back),
          onPressed: () => setState(() => _escaneandoQR = false),
        ),
      ),
      body: Stack(
        children: [
          MobileScanner(onDetect: _onQRDetectado),
          Positioned(
            bottom: 0,
            left: 0,
            right: 0,
            child: Container(
              padding: const EdgeInsets.all(24),
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.topCenter,
                  end: Alignment.bottomCenter,
                  colors: [
                    Colors.transparent,
                    Colors.black.withValues(alpha: 0.8),
                  ],
                ),
              ),
              child: Text(
                l10n.scanHostQR,
                style: Theme.of(
                  context,
                ).textTheme.titleLarge?.copyWith(color: Colors.white),
                textAlign: TextAlign.center,
              ),
            ),
          ),
        ],
      ),
    );
  }

  // ==================== ESPERA ====================

  Widget _buildPantallaEspera(BuildContext context, AppLocalizations l10n) {
    final nearby = context.watch<ServicioNearby>();
    final usuarios = nearby.usuarios;

    return Scaffold(
      appBar: AppBar(
        title: Text(_salaSeleccionada ?? l10n.joinGameTitle),
        leading: IconButton(
          icon: const Icon(Icons.close),
          onPressed: () async {
            final nearby = context.read<ServicioNearby>();
            await nearby.desconectar();
            if (context.mounted) {
              setState(() {
                _buscando = false;
                _conectando = false;
              });
            }
          },
        ),
      ),
      body: FondoFarolero(
        intenso: true,
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(24),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
            EncabezadoFarolero(
              icono: Icons.check_circle,
              titulo: l10n.connectedWaiting,
              subtitulo: '${l10n.yourName}: ${_nombreController.text}',
              color: TemaApp.colorVerde,
              trailing: const SizedBox(
                width: 24,
                height: 24,
                child: CircularProgressIndicator(
                  strokeWidth: 2.4,
                  color: TemaApp.colorNaranja,
                ),
              ),
            ),
            const SizedBox(height: 16),
            Text(
              l10n.waitingForHost,
              style: Theme.of(context).textTheme.bodyMedium,
            ),
            const SizedBox(height: 32),

            // Pool de usuarios disponibles (tarea 3.4)
            if (usuarios.isNotEmpty) ...[
              const Divider(),
              const SizedBox(height: 16),
              Text(
                l10n.availableProfiles,
                style: Theme.of(context).textTheme.titleLarge,
              ),
              const SizedBox(height: 12),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(12),
                  child: Column(
                    children: [
                      // Opción crear nuevo usuario (tarea 3.5)
                      ListTile(
                        leading: const Icon(
                          Icons.add,
                          color: TemaApp.colorAcento,
                        ),
                        title: Text(l10n.createNewUser),
                        onTap: () => _crearNuevoUsuario(context),
                      ),
                      const Divider(),
                      // Usuarios existentes
                      ...usuarios.map(_buildUsuarioSalaTile),
                    ],
                  ),
                ),
              ),
            ] else ...[
              const SizedBox(height: 16),
              // Si no hay usuarios, permitir crear uno
              OutlinedButton.icon(
                onPressed: () => _crearNuevoUsuario(context),
                icon: const Icon(Icons.person_add),
                label: Text(l10n.createNewUser),
              ),
            ],
          ],
          ),
        ),
      ),
    );
  }

  /// Crea un nuevo usuario y lo envía al host
  Future<void> _crearNuevoUsuario(BuildContext context) async {
    final l10n = AppLocalizations.of(context)!;
    final controller = TextEditingController();
    final nearby = context.read<ServicioNearby>();
    final perfil = context.read<ServicioPerfilUsuario>().perfil;
    controller.text = perfil.nombre;

    final nombre = await showDialog<String>(
      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) {
      final gamificacion =
          context.read<ServicioPerfilUsuario>().resumenGamificacion;
      await nearby.crearUsuarioSala(
        nombre.trim(),
        seleccionar: true,
        nick: perfil.nick,
        avatar: perfil.avatarAsset,
        fuego: gamificacion.fuego,
        medallas: gamificacion.medallas,
      );
    }
  }

  /// Env?a el usuario seleccionado/creado al host
  void _enviarUsuarioAlHost(Usuario usuario) {
    final nearby = context.read<ServicioNearby>();
    nearby.seleccionarUsuarioSala(usuario.id);
    ScaffoldMessenger.of(
      context,
    ).showSnackBar(SnackBar(content: Text('${usuario.nombre} seleccionado')));
  }

  Widget _buildUsuarioSalaTile(Usuario usuario) {
    final nearby = context.read<ServicioNearby>();
    final miClientId = nearby.miClientId;
    final seleccionadoPorMi = usuario.clienteIdSeleccionado == miClientId;
    final seleccionadoPorOtro =
        usuario.estaSeleccionado && usuario.clienteIdSeleccionado != miClientId;

    return ListTile(
      leading: AvatarFarolero(
        texto: usuario.nombre.isEmpty ? '?' : usuario.nombre[0],
        assetPath: usuario.avatar,
        size: 38,
        fuego: usuario.fuego,
        medallas: usuario.medallas,
      ),
      title: Text(usuario.nombre),
      subtitle: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            seleccionadoPorMi
                ? 'Seleccionado por este móvil'
                : seleccionadoPorOtro
                    ? 'No disponible'
                    : 'Disponible',
          ),
          if (usuario.medallas.isNotEmpty) ...[
            const SizedBox(height: 4),
            MedallasCompactasFarolero(ids: usuario.medallas),
          ],
        ],
      ),
      trailing: seleccionadoPorMi
          ? IconButton(
              icon: const Icon(Icons.close),
              onPressed: () => nearby.liberarUsuarioSala(usuario.id),
            )
          : null,
      enabled: !seleccionadoPorOtro,
      onTap: seleccionadoPorOtro
          ? null
          : () {
              if (seleccionadoPorMi) {
                nearby.liberarUsuarioSala(usuario.id);
              } else {
                _enviarUsuarioAlHost(usuario);
              }
            },
    );
  }
  // ==================== HELPERS ====================

  Widget _buildError(String msg) {
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: TemaApp.colorAcento.withValues(alpha: 0.1),
        borderRadius: BorderRadius.circular(12),
      ),
      child: Text(
        msg,
        style: const TextStyle(color: TemaApp.colorAcento),
        textAlign: TextAlign.center,
      ),
    );
  }
}
