using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Program
{
    internal class VirusVoid
    {
        public static Dictionary<int, List<int>> Contacts = new Dictionary<int, List<int>>();
        public static HashSet<int> InfectedPeople = new HashSet<int>();
        public static List<int> uniquePeople = new List<int>();
        public static HashSet<int> NewInfectedPeople = new HashSet<int>();

        public static void ListAllInfectionTreeVoid()
        {
            string path = $@"../../../forrasok/elek.txt";

            var data = File.ReadAllLines(path);

            foreach (var item in data)
            {
                string[] nums = item.Split(' ');
                int infector = Convert.ToInt32(nums[0]);
                int infected = Convert.ToInt32(nums[1]);

                if (!uniquePeople.Contains(infector))
                {
                    uniquePeople.Add(infector);
                }

                if (!uniquePeople.Contains(infected))
                {
                    uniquePeople.Add(infected);
                }

                if (Contacts.ContainsKey(infector))
                {
                    Contacts[infector].Add(infected);
                }
                else
                {
                    Contacts[infector] = new List<int> { infected };
                }
            }

            InfectedPeople.Clear(); // Clear the set before starting the spread

            int infectionTreeCount = 0;

            // Spread the virus starting from each unique person if they are not already infected
            foreach (var person in uniquePeople)
            {
                if (!InfectedPeople.Contains(person))
                {
                    infectionTreeCount++;
                    Virus rootVirus = new Virus(person);
                    InfectedPeople.Add(person); // Add the root virus to the infected set
                    SpreadBFS(rootVirus, int.MaxValue); // Spread without depth limit
                }
            }

            Console.WriteLine($"Infected people count: {InfectedPeople.Count}");
            Console.WriteLine($"Unique people count: {uniquePeople.Count}");
            Console.WriteLine($"Number of infection trees: {infectionTreeCount}");

            // Verify if all unique people are infected
            bool allInfected = uniquePeople.All(person => InfectedPeople.Contains(person));
            Console.WriteLine($"All unique people infected: {allInfected}");

            if (!allInfected)
            {
                var notInfected = uniquePeople.Where(person => !InfectedPeople.Contains(person)).ToList();
                Console.WriteLine("People not infected:");
                foreach (var person in notInfected)
                {
                    Console.WriteLine(person);
                }
            }
        }

        public static void Previous()
        {
            string path = $@"../../../forrasok/elek.txt";

            var data = File.ReadAllLines(path);

            foreach (var item in data)
            {
                string[] nums = item.Split(' ');
                int infector = Convert.ToInt32(nums[0]);
                int infected = Convert.ToInt32(nums[1]);

                if (!uniquePeople.Contains(infector))
                {
                    uniquePeople.Add(infector);
                }

                if (!uniquePeople.Contains(infected))
                {
                    uniquePeople.Add(infected);
                }

                if (Contacts.ContainsKey(infector))
                {
                    Contacts[infector].Add(infected);
                }
                else
                {
                    Contacts[infector] = new List<int> { infected };
                }
            }

            Virus rootVirus = new Virus(2);
            InfectedPeople.Clear(); // Clear the set before starting the spread
            InfectedPeople.Add(2); // Add the root virus to the infected set
            SpreadBFS(rootVirus, 5);
            //Spread(rootVirus, 15);

            //rootVirus.PrintInfectionTreeWithDepth(2, 0, "->");
            rootVirus.PrintInfectionTree();

            Console.WriteLine(InfectedPeople.Count);
            Console.WriteLine(rootVirus.CountInfectedInDepthRange(3, 10));

            Console.WriteLine($"Infected people count: {InfectedPeople.Count}");
            Console.WriteLine($"Unique people count: {uniquePeople.Count}");

            // Verify if all unique people are infected
            bool allInfected = uniquePeople.All(person => InfectedPeople.Contains(person));
            Console.WriteLine($"All unique people infected: {allInfected}");

            if (!allInfected)
            {
                var notInfected = uniquePeople.Where(person => !InfectedPeople.Contains(person)).ToList();
                Console.WriteLine("People not infected:");
                foreach (var person in notInfected)
                {
                    Console.WriteLine(person);
                }
            }

            /*
            Virus rootVirus2 = new Virus(2);
            int count = 0;
            while (NewInfectedPeople.Count != uniquePeople.Count)
            {
                count++;
                SpreadBFS(rootVirus2, count);
            }

            Console.WriteLine(count);
            */
        }


        public static void SpreadBFS(Virus rootVirus, int maxDepth)
        {
            Queue<(Virus virus, int depth)> queue = new Queue<(Virus virus, int depth)>();
            queue.Enqueue((rootVirus, 0));

            while (queue.Count > 0)
            {
                var (currentVirus, currentDepth) = queue.Dequeue();

                if (currentDepth >= maxDepth)
                {
                    continue;
                }

                if (Contacts.ContainsKey(currentVirus.Name))
                {
                    foreach (var contact in Contacts[currentVirus.Name])
                    {
                        if (!InfectedPeople.Contains(contact))
                        {
                            Virus newInfected = new Virus(contact, currentDepth + 1);
                            currentVirus.Infect(newInfected);
                            InfectedPeople.Add(contact); // Mark as infected
                            queue.Enqueue((newInfected, currentDepth + 1));
                        }
                    }
                }
            }
        }

        public static void Spread(Virus virus, int maxDepth, int currentDepth = 0)
        {
            if (currentDepth >= maxDepth)
            {
                return;
            }

            if (Contacts.ContainsKey(virus.Name))
            {
                foreach (var contact in Contacts[virus.Name])
                {
                    if (!InfectedPeople.Contains(contact))
                    {
                        Virus newInfected = new Virus(contact);
                        virus.Infect(newInfected);
                        InfectedPeople.Add(contact); // Mark as infected
                        Spread(newInfected, maxDepth, currentDepth + 1);
                    }
                    else
                    {
                        Virus newInfected = new Virus(contact);
                        virus.Infect(newInfected);
                        //InfectedPeople.Add(contact); // Mark as infected
                        Spread(newInfected, maxDepth, currentDepth + 1);
                    }

                }
            }
        }

        /*
        public static void Spread(Virus virus)
        {
            if (Contacts.ContainsKey(virus.Name))
            {
                foreach (var contact in Contacts[virus.Name])
                {
                    if (!InfectedPeople.Contains(contact))
                    {
                        Virus newInfected = new Virus(contact);
                        virus.Infect(newInfected);
                        InfectedPeople.Add(contact); // Mark as infected
                        Spread(newInfected);
                    }
                }
            }
        }
        */
    }
}
