using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using uTank2;
using static uTank2.PluginCore;

namespace MosswartMassacre
{
    /// <summary>
    /// Helper class for working with the VTank plugin
    /// </summary>
    public static unsafe class vTank
    {
        internal static IList ChatQueue = null;
        internal static Type ChatType;

        /// <summary>
        /// The TrustedRelay interface for VTank control
        /// </summary>
        public static cExternalInterfaceTrustedRelay Instance { get; internal set; }

        /// <summary>
        /// Current VTank action locks.  Key is lock type, Value is when the lock is set to expire.
        /// </summary>
        public static Dictionary<uTank2.ActionLockType, DateTime> locks = new Dictionary<uTank2.ActionLockType, DateTime>();

        /// <summary>
        /// Enables VTank helper functionality
        /// </summary>
        public static void Enable()
        {
            foreach (uTank2.ActionLockType ty in Enum.GetValues(typeof(uTank2.ActionLockType)))
                locks[ty] = DateTime.MinValue;

            try
            {
                ConstructorInfo ctor = typeof(cExternalInterfaceTrustedRelay)
                    .GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)[0];
                Instance = (cExternalInterfaceTrustedRelay)ctor.Invoke(new object[] { eExternalsPermissionLevel.None });

                FieldInfo fieldInfo = Instance.GetType()
                    .GetField("a", BindingFlags.NonPublic | BindingFlags.Instance);
                fieldInfo.SetValue(Instance, 15);

                Type vTankChatHandler = typeof(uTank2.PluginCore).Assembly.GetType("a7");
                FieldInfo vTankChatList = vTankChatHandler
                    .GetField("a", BindingFlags.NonPublic | BindingFlags.Static);
                ChatType = vTankChatHandler.GetNestedType("a");
                ChatQueue = (IList)(vTankChatList.GetValue(null));
            }
            catch
            {
                Disable();
            }
        }

        /// <summary>
        /// Disables VTank helper functionality
        /// </summary>
        public static void Disable()
        {
            ChatType = null;
            ChatQueue = null;
            Instance = null;
        }

        /// <summary>
        /// Lock VTank from performing actions. Use Decision_UnLock to cancel.
        /// </summary>
        /// <param name="actionLockType">the type of action to put a lock on</param>
        /// <param name="timeSpan">time to lock vtank for</param>
        public static void Decision_Lock(uTank2.ActionLockType actionLockType, TimeSpan timeSpan)
        {
            Instance?.Decision_Lock(actionLockType, timeSpan);
            DateTime newExp = DateTime.UtcNow + timeSpan;
            if (locks[actionLockType] < newExp) locks[actionLockType] = newExp;
        }

        /// <summary>
        /// Cancel a VTank lock
        /// </summary>
        /// <param name="actionLockType">the type of action to unlock</param>
        public static void Decision_UnLock(uTank2.ActionLockType actionLockType)
        {
            Instance?.Decision_UnLock(actionLockType);
            locks[actionLockType] = DateTime.MinValue;
        }

        #region Tell(string message, int color = 0, int target = 0)
        /// <summary>
        /// Sends a chat message to VTank so that it will be capturable by metas.
        /// </summary>
        /// <param name="message">message to send</param>
        /// <param name="color">color of the chat text</param>
        /// <param name="target">chat window target</param>
        public static void Tell(string message, int color = 0, int target = 0)
        {
            if (ChatQueue != null)
            {
                object newA = Activator.CreateInstance(ChatType);
                ChatType.GetField("a").SetValue(newA, message); // message
                ChatType.GetField("b").SetValue(newA, color);   // color
                ChatType.GetField("c").SetValue(newA, target);  // target
                try
                {
                    ChatQueue.Add(newA);
                }
                catch { }
            }
        }
        #endregion
    }
}
