using Dalamud.Hooking;
using Dalamud.Plugin.Services;
using Dalamud.Utility.Signatures;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI;
using Microsoft.Extensions.Logging;

namespace LightlessSync.Services;

public unsafe sealed class NameplateUpdateHookService : IDisposable
{
    private delegate nint UpdateNameplateDelegate(RaptureAtkModule* raptureAtkModule, RaptureAtkModule.NamePlateInfo* namePlateInfo,
        NumberArrayData* numArray, StringArrayData* stringArray, BattleChara* battleChara, int numArrayIndex, int stringArrayIndex);
    public delegate void NameplateUpdatedHandler(RaptureAtkModule* raptureAtkModule, RaptureAtkModule.NamePlateInfo* namePlateInfo,
        NumberArrayData* numArray, StringArrayData* stringArray, BattleChara* battleChara, int numArrayIndex, int stringArrayIndex);

    // Glyceri, Thanks :bow:
    [Signature("40 53 55 57 41 56 48 81 EC ?? ?? ?? ?? 48 8B 84 24", DetourName = nameof(UpdateNameplateDetour))]
    private readonly Hook<UpdateNameplateDelegate>? _nameplateHook = null;

    private readonly ILogger<NameplateUpdateHookService> _logger;

    public NameplateUpdateHookService(ILogger<NameplateUpdateHookService> logger, IGameInteropProvider interop)
    {
        _logger = logger;

        interop.InitializeFromAttributes(this);
        _nameplateHook?.Enable();
    }

    public event NameplateUpdatedHandler? NameplateUpdated;

    /// <summary>
    /// Detour for the game's internal nameplate update function.
    /// This will be called whenever the client updates any nameplate.
    /// </summary>
    private nint UpdateNameplateDetour(RaptureAtkModule* raptureAtkModule, RaptureAtkModule.NamePlateInfo* namePlateInfo,
        NumberArrayData* numArray, StringArrayData* stringArray, BattleChara* battleChara, int numArrayIndex, int stringArrayIndex)
    {
        try
        {
            NameplateUpdated?.Invoke(raptureAtkModule, namePlateInfo, numArray, stringArray, battleChara, numArrayIndex, stringArrayIndex);
        }
        catch (Exception e)
        {
            _logger.LogError(e, "Error in NameplateUpdateHookService UpdateNameplateDetour");
        }

        return _nameplateHook!.Original(raptureAtkModule, namePlateInfo, numArray, stringArray, battleChara, numArrayIndex, stringArrayIndex);
    }

    public void Dispose()
    {
        _nameplateHook?.Dispose();
    }
}
