// Alyios Automation Studio - Input Core
// Professional input simulation and recording

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace AlyiosAutomation.Core
{
    // Input simulator
    public static class InputSimulator
    {
        [DllImport("user32.dll")]
        static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, int dwExtraInfo);

        [DllImport("user32.dll")]
        static extern bool SetCursorPos(int x, int y);

        [DllImport("user32.dll")]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);

        [DllImport("user32.dll")]
        static extern short VkKeyScan(char ch);

        const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
        const uint MOUSEEVENTF_LEFTUP = 0x0004;
        const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
        const uint MOUSEEVENTF_RIGHTUP = 0x0010;
        const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        const uint MOUSEEVENTF_MIDDLEUP = 0x0040;
        const uint KEYEVENTF_KEYUP = 0x0002;

        public static void Click(int x, int y, string button, int clicks)
        {
            SetCursorPos(x, y);
            Thread.Sleep(50);

            uint downEvent, upEvent;
            switch (button.ToLower())
            {
                case "right":
                    downEvent = MOUSEEVENTF_RIGHTDOWN;
                    upEvent = MOUSEEVENTF_RIGHTUP;
                    break;
                case "middle":
                    downEvent = MOUSEEVENTF_MIDDLEDOWN;
                    upEvent = MOUSEEVENTF_MIDDLEUP;
                    break;
                default:
                    downEvent = MOUSEEVENTF_LEFTDOWN;
                    upEvent = MOUSEEVENTF_LEFTUP;
                    break;
            }

            for (int i = 0; i < clicks; i++)
            {
                mouse_event(downEvent, 0, 0, 0, 0);
                Thread.Sleep(10);
                mouse_event(upEvent, 0, 0, 0, 0);
                if (i < clicks - 1) Thread.Sleep(100);
            }
        }

        public static void MoveMouse(int x, int y)
        {
            SetCursorPos(x, y);
        }

        public static void PressKey(string key)
        {
            byte vk = GetVirtualKeyCode(key);
            keybd_event(vk, 0, 0, 0);
            Thread.Sleep(10);
            keybd_event(vk, 0, KEYEVENTF_KEYUP, 0);
        }

        public static void SendKeys(string combination)
        {
            string[] parts = combination.Split('+');
            List<byte> keys = new List<byte>();

            foreach (string part in parts)
            {
                keys.Add(GetVirtualKeyCode(part.Trim()));
            }

            foreach (byte vk in keys)
            {
                keybd_event(vk, 0, 0, 0);
                Thread.Sleep(10);
            }

            for (int i = keys.Count - 1; i >= 0; i--)
            {
                keybd_event(keys[i], 0, KEYEVENTF_KEYUP, 0);
                Thread.Sleep(10);
            }
        }

        public static void TypeText(string text, int delayMs = 10)
        {
            foreach (char c in text)
            {
                short vk = VkKeyScan(c);
                byte vkCode = (byte)(vk & 0xFF);
                byte shiftState = (byte)(vk >> 8);

                if ((shiftState & 1) != 0)
                {
                    keybd_event(0x10, 0, 0, 0);
                    Thread.Sleep(10);
                }

                keybd_event(vkCode, 0, 0, 0);
                Thread.Sleep(10);
                keybd_event(vkCode, 0, KEYEVENTF_KEYUP, 0);

                if ((shiftState & 1) != 0)
                {
                    Thread.Sleep(10);
                    keybd_event(0x10, 0, KEYEVENTF_KEYUP, 0);
                }

                Thread.Sleep(delayMs);
            }
        }

        static byte GetVirtualKeyCode(string key)
        {
            var keys = new Dictionary<string, byte>
            {
                {"enter", 0x0D}, {"esc", 0x1B}, {"space", 0x20},
                {"tab", 0x09}, {"backspace", 0x08}, {"delete", 0x2E},
                {"up", 0x26}, {"down", 0x28}, {"left", 0x25}, {"right", 0x27},
                {"home", 0x24}, {"end", 0x23}, {"pageup", 0x21}, {"pagedown", 0x22},
                {"f1", 0x70}, {"f2", 0x71}, {"f3", 0x72}, {"f4", 0x73},
                {"f5", 0x74}, {"f6", 0x75}, {"f7", 0x76}, {"f8", 0x77},
                {"f9", 0x78}, {"f10", 0x79}, {"f11", 0x7A}, {"f12", 0x7B},
                {"ctrl", 0x11}, {"shift", 0x10}, {"alt", 0x12}, {"win", 0x5B}
            };

            if (keys.ContainsKey(key.ToLower()))
                return keys[key.ToLower()];

            if (key.Length == 1)
                return (byte)char.ToUpper(key[0]);

            return 0;
        }
    }

    // Mouse hook for recording
    public class MouseHook : IDisposable
    {
        [DllImport("user32.dll")]
        static extern IntPtr SetWindowsHookEx(int idHook, HookProc callback, IntPtr hInstance, uint threadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookEx(IntPtr hInstance);

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibrary(string lpFileName);

        [DllImport("user32.dll")]
        static extern bool GetCursorPos(out POINT lpPoint);

        delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        const int WH_MOUSE_LL = 14;
        const int WM_LBUTTONDOWN = 0x0201;
        const int WM_RBUTTONDOWN = 0x0204;
        const int WM_MBUTTONDOWN = 0x0207;
        const int WM_MOUSEMOVE = 0x0200;

        IntPtr hookID = IntPtr.Zero;
        HookProc hookProc;

        public event Action<int, int, string> OnClick;
        public event Action<int, int> OnMove;

        public MouseHook()
        {
            hookProc = HookCallback;
        }

        public void Start()
        {
            if (hookID == IntPtr.Zero)
            {
                hookID = SetWindowsHookEx(WH_MOUSE_LL, hookProc, LoadLibrary("user32"), 0);
            }
        }

        public void Stop()
        {
            if (hookID != IntPtr.Zero)
            {
                UnhookWindowsHookEx(hookID);
                hookID = IntPtr.Zero;
            }
        }

        IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                int msg = wParam.ToInt32();
                var hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));

                if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN)
                {
                    string button = msg == WM_RBUTTONDOWN ? "Right" :
                                  msg == WM_MBUTTONDOWN ? "Middle" : "Left";
                    if (OnClick != null)
                        OnClick(hookStruct.pt.x, hookStruct.pt.y, button);
                }
                else if (msg == WM_MOUSEMOVE)
                {
                    if (OnMove != null)
                        OnMove(hookStruct.pt.x, hookStruct.pt.y);
                }
            }
            return CallNextHookEx(hookID, nCode, wParam, lParam);
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        public void Dispose()
        {
            Stop();
        }
    }

    // Keyboard hook
    public class KeyboardHook : IDisposable
    {
        [DllImport("user32.dll")]
        static extern IntPtr SetWindowsHookEx(int idHook, HookProc callback, IntPtr hInstance, uint threadId);

        [DllImport("user32.dll")]
        static extern bool UnhookWindowsHookEx(IntPtr hInstance);

        [DllImport("user32.dll")]
        static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll")]
        static extern IntPtr LoadLibrary(string lpFileName);

        delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        const int WH_KEYBOARD_LL = 13;
        const int WM_KEYDOWN = 0x0100;

        IntPtr hookID = IntPtr.Zero;
        HookProc hookProc;

        public event Action<string, bool> OnKeyEvent;

        public KeyboardHook()
        {
            hookProc = HookCallback;
        }

        public void Start()
        {
            if (hookID == IntPtr.Zero)
            {
                hookID = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, LoadLibrary("user32"), 0);
            }
        }

        public void Stop()
        {
            if (hookID != IntPtr.Zero)
            {
                UnhookWindowsHookEx(hookID);
                hookID = IntPtr.Zero;
            }
        }

        IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam.ToInt32() == WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                string keyName = ((Keys)vkCode).ToString();

                if (OnKeyEvent != null)
                    OnKeyEvent(keyName, true);
            }
            return CallNextHookEx(hookID, nCode, wParam, lParam);
        }

        public void Dispose()
        {
            Stop();
        }
    }

    // Screen capture
    public static class ScreenCapture
    {
        public static void CaptureScreen(string filePath, Rectangle region)
        {
            Rectangle bounds = region == Rectangle.Empty ?
                Screen.PrimaryScreen.Bounds : region;

            using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    g.CopyFromScreen(bounds.Left, bounds.Top, 0, 0, bounds.Size);
                }

                ImageFormat format = ImageFormat.Png;
                string ext = System.IO.Path.GetExtension(filePath).ToLower();
                if (ext == ".jpg" || ext == ".jpeg")
                    format = ImageFormat.Jpeg;
                else if (ext == ".bmp")
                    format = ImageFormat.Bmp;

                bitmap.Save(filePath, format);
            }
        }

        public static Bitmap CaptureRegion(Rectangle region)
        {
            Bitmap bitmap = new Bitmap(region.Width, region.Height);
            using (Graphics g = Graphics.FromImage(bitmap))
            {
                g.CopyFromScreen(region.Left, region.Top, 0, 0, region.Size);
            }
            return bitmap;
        }
    }

    // Window helper
    public static class WindowHelper
    {
        [DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder text, int count);

        [DllImport("user32.dll")]
        static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        public static string GetActiveWindowTitle()
        {
            IntPtr handle = GetForegroundWindow();
            System.Text.StringBuilder text = new System.Text.StringBuilder(256);
            GetWindowText(handle, text, 256);
            return text.ToString();
        }

        public static Rectangle GetActiveWindowRect()
        {
            IntPtr handle = GetForegroundWindow();
            RECT rect;
            GetWindowRect(handle, out rect);
            return new Rectangle(rect.Left, rect.Top,
                rect.Right - rect.Left, rect.Bottom - rect.Top);
        }
    }
}
