using System.Runtime.InteropServices;
using NyxCS2.Core;
using NyxCS2.UI;

namespace NyxCS2;

internal static class Program
{
    public const string Version = "2.3";

    [STAThread]
    private static void Main()
    {
        SetProcessDpiAwarenessContext(new IntPtr(-4)); // PER_MONITOR_AWARE_V2 - keeps overlay/cursor pixels honest
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        // any message-processing exception gets logged to nyx.log instead of
        // showing the "Exception processing message" dialog and killing the app
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        Application.ThreadException += (_, e) => CrashLog("thread", e.Exception);
        AppDomain.CurrentDomain.UnhandledException += (_, e) => CrashLog("domain", e.ExceptionObject as Exception ?? new Exception("unknown (" + (e.IsTerminating ? "fatal" : "non-fatal") + ")"));

        var s = new AppSettings();
        var engine = new Engine(s);
        var overlay = new OverlayForm(() => engine.Snap, s);
        var menu = new MenuForm(engine, s, overlay);

        overlay.Show();
        engine.Start();
        OffsetUpdater.Start();   // pull newest offsets in the background (like other menus)

        var hot = new Thread(HotkeyLoop) { IsBackground = true };
        hot.Start((menu, overlay));

        Application.Run(menu);
        engine.Stop();
    }

    // INSERT toggles the overlay, END toggles the menu. Polled so the
    // click-through overlay never needs keyboard focus.
    private static void HotkeyLoop(object box)
    {
        (MenuForm menu, OverlayForm overlay) = ((MenuForm, OverlayForm))box;
        while (true)
        {
            if ((GetAsyncKeyState(0x2D) & 1) != 0) overlay.Toggle(); // VK_INSERT
            if ((GetAsyncKeyState(0x23) & 1) != 0) menu.Toggle();    // VK_END
            Thread.Sleep(100);
        }
    }

    private static void CrashLog(string src, Exception ex)
    {
        try
        {
            File.AppendAllText(Path.Combine(AppContext.BaseDirectory, "nyx.log"),
                $"[{DateTime.Now:HH:mm:ss}] UNHANDLED ({src}): {ex}\r\n");
        }
        catch { }
    }

    [DllImport("user32.dll")]
    private static extern short GetAsyncKeyState(int vKey);
    [DllImport("user32.dll")]
    internal static extern bool SetProcessDpiAwarenessContext(IntPtr value);
}