using Dalamud.IoC;
using Dalamud.Logging;
using Dalamud.Plugin;
using Dalamud.Plugin.Ipc;
using PatMe2Mqtt.PatMeProxyApi;
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;

namespace PatMe2Mqtt
{
    public sealed class Plugin : IDalamudPlugin
    {
        private readonly List<Cmd> _cmds;
        private readonly ICallGateSubscriber<string, ushort, string, uint, object> _ipcPatMeCounter;
        private readonly ICallGateSubscriber<string, string, bool> _ipcMqttPublish;

        public Plugin([RequiredVersion("1.0")] DalamudPluginInterface pluginInterface)
        {
            pluginInterface.Create<Service>();

            Service.Plugin = this;
            Service.PatMe = new();

            _cmds = typeof(Plugin).Assembly.GetTypes()
                .Where(t => !t.IsAbstract && typeof(Cmd).IsAssignableFrom(t))
                .Select(t => (Cmd) Activator.CreateInstance(t)!)
                .ToList();

            foreach (Cmd cmd in _cmds)
            {
                cmd.Register(Service.CommandManager);
            }

            _ipcPatMeCounter = pluginInterface.GetIpcSubscriber<string, ushort, string, uint, object>("patMeEmoteCounter");
            _ipcMqttPublish = pluginInterface.GetIpcSubscriber<string, string, bool>("Ffxiv2Mqtt.Publish");

            SyncAll();

            Service.ClientState.Login += OnLogIn;
            _ipcPatMeCounter.Subscribe(OnPatMeEmote);
        }

        public string Name => "PatMe2Mqtt";

        public void Dispose()
        {
            Service.ClientState.Login -= OnLogIn;
            _ipcPatMeCounter.Unsubscribe(OnPatMeEmote);

            foreach (Cmd cmd in _cmds)
            {
                cmd.Dispose();
            }

            Service.Plugin = null!;
        }

        public void SyncAll()
        {
            try
            {
                if (!Service.PatMe.Refresh())
                {
                    return;
                }

                foreach (var emoteCounter in Service.PatMe.EmoteCounters)
                {
                    Sync(emoteCounter);
                }
            }
            catch (Exception e)
            {
                Service.PluginLog.Error(e, "PatMe2Mqtt couldn't SyncAll");
            }
        }

        private void SyncByDescSingular(string descSingular)
        {
            try
            {
                if (!Service.PatMe.Refresh())
                {
                    return;
                }

                foreach (var emoteCounter in Service.PatMe.EmoteCounters)
                {
                    if (emoteCounter.descSingular == descSingular)
                    {
                        Sync(emoteCounter);
                    }
                }
            }
            catch (Exception e)
            {
                Service.PluginLog.Error(e, "PatMe2Mqtt couldn't SyncByDescSingular({0})", descSingular);
            }
        }

        private void Sync(EmoteCounter counter)
        {
            var topic = $"patme/{Service.ClientState.LocalContentId}/{counter.descPlural}";
            var value = counter.Value.ToString();

            try
            {
                _ipcMqttPublish.InvokeFunc(topic, value);
            }
            catch (Exception e)
            {
                Service.PluginLog.Warning(e, "PatMe2Mqtt couldn't Sync(\"{0}\", {1})", topic, value);
            }
        }

        private void OnLogIn()
        {
            Service.Framework.RunOnTick(SyncAll, delayTicks: 10);
        }

        private void OnPatMeEmote(string descSingular, ushort emoteId, string instigatorName, uint instigatorWorld)
        {
            SyncByDescSingular(descSingular);
        }
    }
}