import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../modelos/partida.dart';
import '../modelos/snapshot_partida_online.dart';

class ResultadoPartidaGuardado {
  final String id;
  final DateTime fecha;
  final bool modoMultimovil;
  final int jugadores;
  final int impostores;
  final int rondas;
  final String ganador;
  final String palabra;
  final String categoria;

  const ResultadoPartidaGuardado({
    required this.id,
    required this.fecha,
    required this.modoMultimovil,
    required this.jugadores,
    required this.impostores,
    required this.rondas,
    required this.ganador,
    required this.palabra,
    required this.categoria,
  });

  factory ResultadoPartidaGuardado.desdePartida(Partida partida) {
    return ResultadoPartidaGuardado(
      id: DateTime.now().microsecondsSinceEpoch.toString(),
      fecha: DateTime.now(),
      modoMultimovil: partida.config.modoMultimovil,
      jugadores: partida.jugadores.length,
      impostores: partida.impostoresTotales,
      rondas: partida.rondaActual,
      ganador: partida.ganador ?? 'sin_resultado',
      palabra: partida.palabraSecreta,
      categoria: partida.categoriaReal,
    );
  }

  factory ResultadoPartidaGuardado.desdeSnapshotOnline(
    SnapshotPartidaOnline snapshot,
  ) {
    final impostores = snapshot.impostores.isNotEmpty
        ? snapshot.impostores.length
        : snapshot.jugadores.where((jugador) => jugador.esImpostor).length;
    return ResultadoPartidaGuardado(
      id: 'online-${snapshot.roomId ?? DateTime.now().microsecondsSinceEpoch}',
      fecha: DateTime.now(),
      modoMultimovil: true,
      jugadores: snapshot.jugadores.length,
      impostores: impostores,
      rondas: snapshot.ronda,
      ganador: snapshot.ganador ?? 'sin_resultado',
      palabra: snapshot.palabraSecreta ?? '',
      categoria: snapshot.categoria,
    );
  }

  Map<String, dynamic> toJson() => {
        'id': id,
        'fecha': fecha.toIso8601String(),
        'modoMultimovil': modoMultimovil,
        'jugadores': jugadores,
        'impostores': impostores,
        'rondas': rondas,
        'ganador': ganador,
        'palabra': palabra,
        'categoria': categoria,
      };

  factory ResultadoPartidaGuardado.fromJson(Map<String, dynamic> json) {
    return ResultadoPartidaGuardado(
      id: json['id'] as String,
      fecha: DateTime.parse(json['fecha'] as String),
      modoMultimovil: json['modoMultimovil'] as bool? ?? false,
      jugadores: json['jugadores'] as int? ?? 0,
      impostores: json['impostores'] as int? ?? 0,
      rondas: json['rondas'] as int? ?? 0,
      ganador: json['ganador'] as String? ?? 'sin_resultado',
      palabra: json['palabra'] as String? ?? '',
      categoria: json['categoria'] as String? ?? '',
    );
  }
}

class ServicioHistorialPartidas extends ChangeNotifier {
  static const _clave = 'historial.partidas';
  final List<ResultadoPartidaGuardado> _partidas = [];
  bool _cargado = false;

  List<ResultadoPartidaGuardado> get partidas => List.unmodifiable(_partidas);
  bool get cargado => _cargado;

  Future<void> cargar() async {
    final prefs = await SharedPreferences.getInstance();
    final raw = prefs.getString(_clave);
    _partidas.clear();
    if (raw != null) {
      final lista = json.decode(raw) as List<dynamic>;
      _partidas.addAll(
        lista.map((e) => ResultadoPartidaGuardado.fromJson(e as Map<String, dynamic>)),
      );
    }
    _cargado = true;
    notifyListeners();
  }

  Future<void> guardarPartida(Partida partida) async {
    if (partida.ganador == null) return;
    _partidas.insert(0, ResultadoPartidaGuardado.desdePartida(partida));
    if (_partidas.length > 100) _partidas.removeRange(100, _partidas.length);
    await _persistir();
    notifyListeners();
  }

  Future<void> guardarSnapshotOnline(SnapshotPartidaOnline snapshot) async {
    if (snapshot.ganador == null || snapshot.palabraSecreta == null) return;
    final guardado = ResultadoPartidaGuardado.desdeSnapshotOnline(snapshot);
    if (_partidas.any((partida) => partida.id == guardado.id)) return;
    _partidas.insert(0, guardado);
    if (_partidas.length > 100) _partidas.removeRange(100, _partidas.length);
    await _persistir();
    notifyListeners();
  }

  Future<void> limpiar() async {
    _partidas.clear();
    await _persistir();
    notifyListeners();
  }

  Future<void> _persistir() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(
      _clave,
      json.encode(_partidas.map((p) => p.toJson()).toList()),
    );
  }
}
