using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class PopulationManager : MonoBehaviour
{
    public GameObject agentPrefab;
    public Transform target;
    public int populationSize = 20;
    public int geneLength = 100; // Aumentado para más pasos
    public float mutationRate = 0.1f;
    public float generationDuration = 10f; // Más tiempo por generación

    private List<Agente> agents = new List<Agente>();
    private float elapsedTime = 0f;
    private int generation = 1;
    private bool isEvaluating = true;

    void Start()
    {
        SpawnPopulation();
    }

    void Update()
    {
        if (!isEvaluating) return;

        elapsedTime += Time.deltaTime;
        if (elapsedTime >= generationDuration)
        {
            isEvaluating = false;
            EvolveGeneration();
        }
    }

    void SpawnPopulation()
    {
        // Limpiar agentes anteriores
        foreach (var agent in agents)
        {
            if (agent != null) Destroy(agent.gameObject);
        }
        agents.Clear();

        for (int i = 0; i < populationSize; i++)
        {
            Vector3 spawnPos = GetSpawnPosition(i);
            GameObject go = Instantiate(agentPrefab, spawnPos, Quaternion.identity);
            Agente agent = go.GetComponent<Agente>();
            ADN adn = new ADN(geneLength, 8); // 8 direcciones posibles
            agent.Init(adn, target);
            agents.Add(agent);

            go.name = $"Agent_{i}";
        }

        Debug.Log($"✅ Población inicial spawneda: {agents.Count} agentes");
    }

    private Vector3 GetSpawnPosition(int index)
    {
        // Spawn en línea frente al target
        float spacing = 1.5f;
        float x = (index - populationSize / 2) * spacing;
        return transform.position + new Vector3(x, 0, 0);
    }

    void EvolveGeneration()
    {
        Debug.Log($"🔄 Evolucionando generación {generation}...");

        // Detener movimiento
        foreach (var agent in agents)
        {
            agent.StopMoving();
        }

        // Procesar inmediatamente sin corrutina
        ProcessEvolution();
    }

    void ProcessEvolution()
    {
        // Ordenar por fitness
        var sortedAgents = agents.OrderByDescending(a => a.GetFitness()).ToList();
        List<ADN> newPopulation = new List<ADN>();

        // ELITISMO - mantener los mejores 4
        int eliteCount = 4;
        for (int i = 0; i < eliteCount && i < sortedAgents.Count; i++)
        {
            newPopulation.Add(new ADN(sortedAgents[i].adn));
            Debug.Log($"🏆 Elite {i + 1} - Fitness: {sortedAgents[i].GetFitness():F2}");
        }

        // CREAR HIJOS
        while (newPopulation.Count < populationSize)
        {
            // Seleccionar padres solo del top 50%
            int parent1Index = Random.Range(0, populationSize / 2);
            int parent2Index = Random.Range(0, populationSize / 2);

            ADN child = sortedAgents[parent1Index].adn.Crossover(sortedAgents[parent2Index].adn);
            child.Mutate(mutationRate);
            newPopulation.Add(child);
        }

        // APLICAR NUEVA POBLACIÓN
        for (int i = 0; i < agents.Count; i++)
        {
            Vector3 spawnPos = GetSpawnPosition(i);
            agents[i].transform.position = spawnPos;
            agents[i].ResetAgent();
            agents[i].Init(newPopulation[i], target);
        }

        // ESTADÍSTICAS
        float bestFitness = sortedAgents[0].GetFitness();
        float avgFitness = agents.Average(a => a.GetFitness());
        float bestDistance = Vector3.Distance(sortedAgents[0].transform.position, target.position);
        int agentsReached = agents.Count(a => Vector3.Distance(a.transform.position, target.position) < 1f);

        Debug.Log($"=================================");
        Debug.Log($"🏁 GENERACIÓN {generation} COMPLETADA");
        Debug.Log($"🎯 Agentes que llegaron: {agentsReached}/{populationSize}");
        Debug.Log($"📊 Mejor fitness: {bestFitness:F2}");
        Debug.Log($"📈 Fitness promedio: {avgFitness:F2}");
        Debug.Log($"📏 Mejor distancia: {bestDistance:F2}");
        Debug.Log($"=================================");

        generation++;
        elapsedTime = 0f;
        isEvaluating = true;
    }

    void OnDrawGizmos()
    {
        if (target != null)
        {
            // Target
            Gizmos.color = Color.green;
            Gizmos.DrawSphere(target.position, 0.3f);
            Gizmos.DrawWireSphere(target.position, 0.5f);

            // Área de spawn
            Gizmos.color = Color.blue;
            Gizmos.DrawWireCube(transform.position, new Vector3(populationSize * 1.5f, 0.5f, 1f));

            // Línea al target
            Gizmos.color = Color.white;
            Gizmos.DrawLine(transform.position, target.position);
        }
    }
}