using Dalamud.Plugin.Services;
using Dalamud.Game.ClientState.Objects.SubKinds;
using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.UI.Info;
using Microsoft.Extensions.Logging;

namespace LightlessSync.Interop;

public unsafe class BlockedCharacterHandler
{
    private sealed record CharaData(ulong AccId, ulong ContentId);
    private readonly Dictionary<CharaData, bool> _blockedCharacterCache = new();

    private readonly ILogger<BlockedCharacterHandler> _logger;
    private readonly IObjectTable _objectTable;

    public BlockedCharacterHandler(ILogger<BlockedCharacterHandler> logger, IGameInteropProvider gameInteropProvider, IObjectTable objectTable)
    {
        gameInteropProvider.InitializeFromAttributes(this);
        _logger = logger;
        _objectTable = objectTable;
    }

    private CharaData? TryGetIdsFromPlayerPointer(nint ptr, ushort objectIndex)
    {
        if (ptr == nint.Zero || objectIndex >= 200)
            return null;

        var obj = _objectTable[objectIndex];
        if (obj is not IPlayerCharacter player || player.Address != ptr)
            return null;

        var castChar = (BattleChara*)player.Address;
        return new(castChar->Character.AccountId, castChar->Character.ContentId);
    }

    public bool IsCharacterBlocked(nint ptr, ushort objectIndex, out bool firstTime)
    {
        firstTime = false;
        var combined = TryGetIdsFromPlayerPointer(ptr, objectIndex);
        if (combined == null)
            return false;

        if (_blockedCharacterCache.TryGetValue(combined, out var isBlocked))
            return isBlocked;

        firstTime = true;
        var blockStatus = InfoProxyBlacklist.Instance()->GetBlockResultType(combined.AccId, combined.ContentId);
        _logger.LogTrace("CharaPtr {ptr} is BlockStatus: {status}", ptr, blockStatus);
        if ((int)blockStatus == 0)
            return false;
        return _blockedCharacterCache[combined] = blockStatus != InfoProxyBlacklist.BlockResultType.NotBlocked;
    }
}
