using Dalamud.Plugin;
using LightlessSync.Interop.Ipc.Framework;
using LightlessSync.PlayerData.Handlers;
using LightlessSync.Services;
using LightlessSync.Services.ActorTracking;
using LightlessSync.Services.Mediator;
using Microsoft.Extensions.Logging;
using Penumbra.Api.Helpers;
using Penumbra.Api.IpcSubscribers;

namespace LightlessSync.Interop.Ipc.Penumbra;

public sealed class PenumbraResource : PenumbraBase
{
    private readonly ActorObjectService _actorObjectService;
    private readonly GetGameObjectResourcePaths _gameObjectResourcePaths;
    private readonly ResolveGameObjectPath _resolveGameObjectPath;
    private readonly ReverseResolveGameObjectPath _reverseResolveGameObjectPath;
    private readonly ResolvePlayerPathsAsync _resolvePlayerPaths;
    private readonly GetPlayerMetaManipulations _getPlayerMetaManipulations;
    private readonly EventSubscriber<nint, string, string> _gameObjectResourcePathResolved;

    public PenumbraResource(
        ILogger logger,
        IDalamudPluginInterface pluginInterface,
        DalamudUtilService dalamudUtil,
        LightlessMediator mediator,
        ActorObjectService actorObjectService) : base(logger, pluginInterface, dalamudUtil, mediator)
    {
        _actorObjectService = actorObjectService;
        _gameObjectResourcePaths = new GetGameObjectResourcePaths(pluginInterface);
        _resolveGameObjectPath = new ResolveGameObjectPath(pluginInterface);
        _reverseResolveGameObjectPath = new ReverseResolveGameObjectPath(pluginInterface);
        _resolvePlayerPaths = new ResolvePlayerPathsAsync(pluginInterface);
        _getPlayerMetaManipulations = new GetPlayerMetaManipulations(pluginInterface);
        _gameObjectResourcePathResolved = GameObjectResourcePathResolved.Subscriber(pluginInterface, HandleResourceLoaded);
    }

    public override string Name => "Penumbra.Resources";

    public async Task<Dictionary<string, HashSet<string>>?> GetCharacterDataAsync(ILogger logger, GameObjectHandler handler)
    {
        if (!IsAvailable)
        {
            return null;
        }

        return await DalamudUtil.RunOnFrameworkThread(() =>
        {
            logger.LogTrace("Calling On IPC: Penumbra.GetGameObjectResourcePaths");
            var idx = handler.GetGameObject()?.ObjectIndex;
            if (idx == null)
            {
                return null;
            }

            return _gameObjectResourcePaths.Invoke(idx.Value)[0];
        }).ConfigureAwait(false);
    }

    public string GetMetaManipulations()
        => IsAvailable ? _getPlayerMetaManipulations.Invoke() : string.Empty;

    public async Task<(string[] forward, string[][] reverse)> ResolvePathsAsync(string[] forwardPaths, string[] reversePaths)
    {
        if (!IsAvailable)
        {
            return (Array.Empty<string>(), Array.Empty<string[]>());
        }

        return await _resolvePlayerPaths.Invoke(forwardPaths, reversePaths).ConfigureAwait(false);
    }

    public string ResolveGameObjectPath(string gamePath, int gameObjectIndex)
        => IsAvailable ? _resolveGameObjectPath.Invoke(gamePath, gameObjectIndex) : gamePath;

    public string[] ReverseResolveGameObjectPath(string moddedPath, int gameObjectIndex)
        => IsAvailable ? _reverseResolveGameObjectPath.Invoke(moddedPath, gameObjectIndex) : Array.Empty<string>();

    private void HandleResourceLoaded(nint ptr, string gamePath, string resolvedPath)
    {
        if (ptr == nint.Zero)
        {
            return;
        }

        if (!_actorObjectService.TryGetOwnedKind(ptr, out _))
        {
            return;
        }

        if (string.Compare(gamePath, resolvedPath, StringComparison.OrdinalIgnoreCase) == 0)
        {
            return;
        }

        Mediator.Publish(new PenumbraResourceLoadMessage(ptr, gamePath, resolvedPath));
    }

    protected override void HandleStateChange(IpcConnectionState previous, IpcConnectionState current)
    {
    }

    public override void Dispose()
    {
        base.Dispose();
        _gameObjectResourcePathResolved.Dispose();
    }
}
