class MedallaUsuario {
  final String id;
  final String emoji;
  final String assetPath;
  final String nombre;
  final String descripcion;

  const MedallaUsuario({
    required this.id,
    required this.emoji,
    required this.assetPath,
    required this.nombre,
    required this.descripcion,
  });
}

class ResumenGamificacionUsuario {
  final int fuego;
  final List<String> medallas;

  const ResumenGamificacionUsuario({
    required this.fuego,
    required this.medallas,
  });

  Map<String, dynamic> toJson() => {
        'fuego': fuego,
        'medallas': medallas,
      };

  factory ResumenGamificacionUsuario.fromJson(Map<String, dynamic> json) {
    return ResumenGamificacionUsuario(
      fuego: (json['fuego'] as num?)?.toInt() ?? 0,
      medallas: (json['medallas'] as List<dynamic>? ?? const [])
          .map((valor) => valor.toString())
          .toList(),
    );
  }
}

class ProgresoGamificacionUsuario {
  final EstadisticasPerfilUsuario antes;
  final EstadisticasPerfilUsuario despues;
  final List<String> nuevasMedallas;

  const ProgresoGamificacionUsuario({
    required this.antes,
    required this.despues,
    required this.nuevasMedallas,
  });

  int get incrementoFuego => despues.fuego - antes.fuego;
}

class EstadisticasPerfilUsuario {
  final int partidasJugadas;
  final int partidasGanadas;
  final int partidasPerdidas;
  final int partidasComoImpostor;
  final int victoriasComoImpostor;
  final String? fechaUltimaPartidaIso;
  final int partidasHoy;
  final int subidaFuegoHoy;
  final int fuego;

  const EstadisticasPerfilUsuario({
    this.partidasJugadas = 0,
    this.partidasGanadas = 0,
    this.partidasPerdidas = 0,
    this.partidasComoImpostor = 0,
    this.victoriasComoImpostor = 0,
    this.fechaUltimaPartidaIso,
    this.partidasHoy = 0,
    this.subidaFuegoHoy = 0,
    this.fuego = 0,
  });

  static const catalogoMedallas = <String, MedallaUsuario>{
    'novato': MedallaUsuario(id: 'novato', emoji: '🎲', assetPath: 'assets/medals/novato.png', nombre: 'Novato', descripcion: 'Jugó su primera partida.'),
    'habitual': MedallaUsuario(id: 'habitual', emoji: '🧭', assetPath: 'assets/medals/habitual.png', nombre: 'Habitual', descripcion: 'Jugó 10 partidas.'),
    'veterano': MedallaUsuario(id: 'veterano', emoji: '🏛️', assetPath: 'assets/medals/veterano.png', nombre: 'Veterano', descripcion: 'Jugó 50 partidas.'),
    'leyenda': MedallaUsuario(id: 'leyenda', emoji: '👑', assetPath: 'assets/medals/leyenda.png', nombre: 'Leyenda', descripcion: 'Jugó 100 partidas.'),
    'primera_victoria': MedallaUsuario(id: 'primera_victoria', emoji: '🥉', assetPath: 'assets/medals/primera_victoria.png', nombre: 'Primera victoria', descripcion: 'Ganó una partida.'),
    'diez_victorias': MedallaUsuario(id: 'diez_victorias', emoji: '🥈', assetPath: 'assets/medals/diez_victorias.png', nombre: 'Diez victorias', descripcion: 'Ganó 10 partidas.'),
    'veinticinco_victorias': MedallaUsuario(id: 'veinticinco_victorias', emoji: '🥇', assetPath: 'assets/medals/veinticinco_victorias.png', nombre: 'Veinticinco victorias', descripcion: 'Ganó 25 partidas.'),
    'cincuenta_victorias': MedallaUsuario(id: 'cincuenta_victorias', emoji: '💎', assetPath: 'assets/medals/cincuenta_victorias.png', nombre: 'Cincuenta victorias', descripcion: 'Ganó 50 partidas.'),
    'primer_engano': MedallaUsuario(id: 'primer_engano', emoji: '🎭', assetPath: 'assets/medals/primer_engano.png', nombre: 'Primer engaño', descripcion: 'Ganó como impostor.'),
    'impostor_habitual': MedallaUsuario(id: 'impostor_habitual', emoji: '🃏', assetPath: 'assets/medals/impostor_habitual.png', nombre: 'Impostor habitual', descripcion: 'Ganó 5 partidas como impostor.'),
    'lobo_faroles': MedallaUsuario(id: 'lobo_faroles', emoji: '🐺', assetPath: 'assets/medals/lobo_faroles.png', nombre: 'Lobo entre faroles', descripcion: 'Ganó 15 partidas como impostor.'),
    'brasa': MedallaUsuario(id: 'brasa', emoji: '♨️', assetPath: 'assets/medals/brasa.png', nombre: 'Brasa', descripcion: 'Mantiene algo de fuego reciente.'),
    'llama_suave': MedallaUsuario(id: 'llama_suave', emoji: '🔥', assetPath: 'assets/medals/llama_suave.png', nombre: 'Llama suave', descripcion: 'Está jugando con cierta asiduidad.'),
    'llama_fuerte': MedallaUsuario(id: 'llama_fuerte', emoji: '🔥', assetPath: 'assets/medals/llama_fuerte.png', nombre: 'Llama fuerte', descripcion: 'Tiene una asiduidad alta.'),
    'incandescente': MedallaUsuario(id: 'incandescente', emoji: '🌋', assetPath: 'assets/medals/incandescente.png', nombre: 'Incandescente', descripcion: 'Tiene el fuego al máximo.'),
  };

  EstadisticasPerfilUsuario copiar({
    int? partidasJugadas,
    int? partidasGanadas,
    int? partidasPerdidas,
    int? partidasComoImpostor,
    int? victoriasComoImpostor,
    String? fechaUltimaPartidaIso,
    bool limpiarFechaUltimaPartida = false,
    int? partidasHoy,
    int? subidaFuegoHoy,
    int? fuego,
  }) {
    return EstadisticasPerfilUsuario(
      partidasJugadas: partidasJugadas ?? this.partidasJugadas,
      partidasGanadas: partidasGanadas ?? this.partidasGanadas,
      partidasPerdidas: partidasPerdidas ?? this.partidasPerdidas,
      partidasComoImpostor: partidasComoImpostor ?? this.partidasComoImpostor,
      victoriasComoImpostor: victoriasComoImpostor ?? this.victoriasComoImpostor,
      fechaUltimaPartidaIso: limpiarFechaUltimaPartida ? null : (fechaUltimaPartidaIso ?? this.fechaUltimaPartidaIso),
      partidasHoy: partidasHoy ?? this.partidasHoy,
      subidaFuegoHoy: subidaFuegoHoy ?? this.subidaFuegoHoy,
      fuego: (fuego ?? this.fuego).clamp(0, 100).toInt(),
    );
  }

  EstadisticasPerfilUsuario registrarPartida({
    required bool victoria,
    bool comoImpostor = false,
    bool victoriaComoImpostor = false,
    DateTime? fecha,
  }) {
    final momento = fecha ?? DateTime.now();
    final normalizada = DateTime(momento.year, momento.month, momento.day);
    final anterior = _aplicarPasoDeDias(normalizada);
    final ganancia = anterior._gananciaFuegoSiguientePartida();
    return anterior.copiar(
      partidasJugadas: anterior.partidasJugadas + 1,
      partidasGanadas: anterior.partidasGanadas + (victoria ? 1 : 0),
      partidasPerdidas: anterior.partidasPerdidas + (victoria ? 0 : 1),
      partidasComoImpostor: anterior.partidasComoImpostor + (comoImpostor ? 1 : 0),
      victoriasComoImpostor: anterior.victoriasComoImpostor + (victoriaComoImpostor ? 1 : 0),
      fechaUltimaPartidaIso: normalizada.toIso8601String(),
      partidasHoy: anterior.partidasHoy + 1,
      subidaFuegoHoy: anterior.subidaFuegoHoy + ganancia,
      fuego: anterior.fuego + ganancia,
    );
  }

  EstadisticasPerfilUsuario _aplicarPasoDeDias(DateTime hoy) {
    final ultima = fechaUltimaPartidaIso == null ? null : DateTime.tryParse(fechaUltimaPartidaIso!);
    if (ultima == null) return copiar(partidasHoy: 0, subidaFuegoHoy: 0);
    final ultimoDia = DateTime(ultima.year, ultima.month, ultima.day);
    final diferenciaDias = hoy.difference(ultimoDia).inDays;
    if (diferenciaDias <= 0) return this;
    final diasSinJugar = diferenciaDias - 1;
    var fuegoActual = fuego;
    for (var i = 1; i <= diasSinJugar; i++) {
      fuegoActual -= i == 1 ? 3 : (i == 2 ? 5 : 7);
    }
    return copiar(partidasHoy: 0, subidaFuegoHoy: 0, fuego: fuegoActual);
  }

  int _gananciaFuegoSiguientePartida() {
    final numeroPartidaDelDia = partidasHoy + 1;
    final base = switch (numeroPartidaDelDia) { 1 => 6, 2 => 5, 3 => 4, 4 => 3, 5 => 2, _ => 1 };
    final restanteHoy = (25 - subidaFuegoHoy).clamp(0, 25).toInt();
    return base.clamp(0, restanteHoy).toInt();
  }

  List<String> get medallas {
    final resultado = <String>[];
    if (partidasJugadas >= 1) resultado.add('novato');
    if (partidasJugadas >= 10) resultado.add('habitual');
    if (partidasJugadas >= 50) resultado.add('veterano');
    if (partidasJugadas >= 100) resultado.add('leyenda');
    if (partidasGanadas >= 1) resultado.add('primera_victoria');
    if (partidasGanadas >= 10) resultado.add('diez_victorias');
    if (partidasGanadas >= 25) resultado.add('veinticinco_victorias');
    if (partidasGanadas >= 50) resultado.add('cincuenta_victorias');
    if (victoriasComoImpostor >= 1) resultado.add('primer_engano');
    if (victoriasComoImpostor >= 5) resultado.add('impostor_habitual');
    if (victoriasComoImpostor >= 15) resultado.add('lobo_faroles');
    if (fuego >= 100) {
      resultado.add('incandescente');
    } else if (fuego >= 50) {
      resultado.add('llama_fuerte');
    } else if (fuego >= 25) {
      resultado.add('llama_suave');
    } else if (fuego > 0) {
      resultado.add('brasa');
    }
    return resultado;
  }

  List<String> get medallasPrincipales {
    final ids = medallas;
    const prioridad = [
      'incandescente', 'llama_fuerte', 'llama_suave', 'brasa',
      'leyenda', 'veterano', 'habitual', 'novato',
      'cincuenta_victorias', 'veinticinco_victorias', 'diez_victorias', 'primera_victoria',
      'lobo_faroles', 'impostor_habitual', 'primer_engano',
    ];
    return prioridad.where(ids.contains).take(3).toList();
  }

  ResumenGamificacionUsuario get resumen => ResumenGamificacionUsuario(fuego: fuego, medallas: medallasPrincipales);

  Map<String, dynamic> toJson() => {
        'partidasJugadas': partidasJugadas,
        'partidasGanadas': partidasGanadas,
        'partidasPerdidas': partidasPerdidas,
        'partidasComoImpostor': partidasComoImpostor,
        'victoriasComoImpostor': victoriasComoImpostor,
        if (fechaUltimaPartidaIso != null) 'fechaUltimaPartidaIso': fechaUltimaPartidaIso,
        'partidasHoy': partidasHoy,
        'subidaFuegoHoy': subidaFuegoHoy,
        'fuego': fuego,
      };

  factory EstadisticasPerfilUsuario.fromJson(Map<String, dynamic> json) {
    return EstadisticasPerfilUsuario(
      partidasJugadas: (json['partidasJugadas'] as num?)?.toInt() ?? 0,
      partidasGanadas: (json['partidasGanadas'] as num?)?.toInt() ?? 0,
      partidasPerdidas: (json['partidasPerdidas'] as num?)?.toInt() ?? 0,
      partidasComoImpostor: (json['partidasComoImpostor'] as num?)?.toInt() ?? 0,
      victoriasComoImpostor: (json['victoriasComoImpostor'] as num?)?.toInt() ?? 0,
      fechaUltimaPartidaIso: json['fechaUltimaPartidaIso'] as String?,
      partidasHoy: (json['partidasHoy'] as num?)?.toInt() ?? 0,
      subidaFuegoHoy: (json['subidaFuegoHoy'] as num?)?.toInt() ?? 0,
      fuego: (json['fuego'] as num?)?.toInt() ?? 0,
    );
  }
}
