using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Dalamud.Game.Command;
using Dalamud.Game.Gui;
using Dalamud.IoC;
using Dalamud.Logging;
using Dalamud.Plugin;

namespace MultiboxMutexer;

public sealed class Plugin : IDalamudPlugin, IDisposable
{
	[Flags]
	private enum ProcessAccessFlags : uint
	{
		All = 0x1F0FFFu,
		Terminate = 1u,
		CreateThread = 2u,
		VMOperation = 8u,
		VMRead = 0x10u,
		VMWrite = 0x20u,
		DupHandle = 0x40u,
		SetInformation = 0x200u,
		QueryInformation = 0x400u,
		Synchronize = 0x100000u
	}

	[Flags]
	private enum DuplicateOptions : uint
	{
		DUPLICATE_CLOSE_SOURCE = 1u,
		DUPLICATE_SAME_ACCESS = 2u
	}

	private const uint PROCESS_DUP_HANDLE = 64u;

	public string Name => "Multibox Mutexer";

	public DalamudPluginInterface PluginInterface { get; }

	public CommandManager CommandManager { get; }

	[DllImport("kernel32.dll", SetLastError = true)]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool CloseHandle(nint hObject);

	[DllImport("kernel32.dll")]
	private static extern nint OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, nint dwProcessId);

	[DllImport("kernel32.dll", SetLastError = true)]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool DuplicateHandle(nint hSourceProcessHandle, nint hSourceHandle, nint hTargetProcessHandle, out nint lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, DuplicateOptions dwOptions);

	public static bool CloseHandleEx(nint pid, nint handle)
	{
		nint num = OpenProcess(ProcessAccessFlags.DupHandle, bInheritHandle: false, pid);
		nint lpTargetHandle = IntPtr.Zero;
		bool result = DuplicateHandle(num, handle, IntPtr.Zero, out lpTargetHandle, 0u, bInheritHandle: false, DuplicateOptions.DUPLICATE_CLOSE_SOURCE);
		CloseHandle(num);
		return result;
	}

	public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface, [RequiredVersion("1.0")] CommandManager commandManager, [RequiredVersion("1.0")] GameGui gameGui)
	{
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Expected O, but got Unknown
		//IL_002b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_0040: Expected O, but got Unknown
		PluginInterface = pluginInterface;
		CommandManager = commandManager;
		CommandManager.AddHandler("/mutex", new CommandInfo(new HandlerDelegate(OnCommand))
		{
			HelpMessage = "Fix mutex"
		});
		PluginLog.Debug("LOADED?", Array.Empty<object>());
		Process currentProcess = Process.GetCurrentProcess();
		PluginLog.Debug("CURRENT PROCESS PID: " + currentProcess.Id, Array.Empty<object>());
		ReleaseAllMutexes(currentProcess);
	}

	public void ReleaseAllMutexes(Process proc)
	{
		PluginLog.Debug("MUTEXER CALLED", Array.Empty<object>());
		if (HandleManager.ClearMutex())
		{
			PluginLog.Debug("Succesfully killed the mutex", Array.Empty<object>());
		}
		else
		{
			PluginLog.Warning("Failed to kill mutex!", Array.Empty<object>());
		}
	}

	private void OnCommand(string command, string args)
	{
		PluginLog.Debug("RUNNING MUTEXER", Array.Empty<object>());
		Process currentProcess = Process.GetCurrentProcess();
		ReleaseAllMutexes(currentProcess);
	}

	public void Dispose()
	{
		CommandManager.RemoveHandler("/mutex");
	}
}
