using System;

namespace MosswartMassacre
{
    /// <summary>
    /// Provides helper methods to control VTank from within your plugin.
    /// </summary>
    public static class VtankControl
    {
        /// <summary>
        /// Sends a chat command to VTank to switch its current meta-state.
        /// </summary>
        /// <param name="state">
        /// The name of the VTank meta-state to activate.
        /// </param>
        /// <returns>Always returns 1 on sending the command.</returns>
        public static double VtSetMetaState(string state)
        {
            // Dispatch a local chat command that VTank will interpret.
            PluginCore.Decal_DispatchOnChatCommand($"/vt setmetastate {state}");
            return 1;
        }

        /// <summary>
        /// Queries VTank for its currently active meta-state.
        /// </summary>
        /// <returns>
        /// The name of the current meta-state, or empty string if VTank isn’t initialized.
        /// </returns>
        public static string VtGetMetaState()
        {
            // Instance.CurrentMetaState is typed as object, so cast it:
            return (vTank.Instance.CurrentMetaState as string) ?? string.Empty;
        }

        /// <summary>
        /// Attempts to set a VTank configuration value by name.
        /// </summary>
        /// <param name="setting">
        /// The VTank setting key (e.g. “EnableCombat”, “RingDistance”).
        /// </param>
        /// <param name="value">
        /// The string or numeric value to assign. Numeric strings will be parsed.
        /// </param>
        /// <returns>
        /// 1 if the setting was applied or possibly applied; 0 on known failure.
        /// </returns>
        public static double VtSetSetting(string setting, string value)
        {
            try
            {
                var settingType = vTank.Instance.GetSettingType(setting);

                if (settingType == typeof(string))
                {
                    vTank.Instance.SetSetting(setting, value);
                }
                else if (double.TryParse(value, out double number))
                {
                    if (settingType == typeof(bool))
                        vTank.Instance.SetSetting(setting, number == 1);
                    else if (settingType == typeof(double))
                        vTank.Instance.SetSetting(setting, number);
                    else if (settingType == typeof(int))
                        vTank.Instance.SetSetting(setting, Convert.ToInt32(number));
                    else if (settingType == typeof(float))
                        vTank.Instance.SetSetting(setting, Convert.ToSingle(number));
                }
                else
                {
                    // Value wasn’t parseable—report failure
                    return 0;
                }
            }
            catch (Exception ex)
            {
                PluginCore.WriteToChat($"[VTank] SetSetting error ({setting}): {ex.Message}");
                return 0;
            }

            return 1;
        }

        /// <summary>
        /// Reads back a VTank configuration value as a string.
        /// </summary>
        /// <param name="setting">The name of the setting to read.</param>
        /// <returns>
        /// The raw string form of the setting, or empty string if undefined.
        /// </returns>
        public static string VtGetSetting(string setting)
        {
            var val = vTank.Instance.GetSetting(setting);
            return (val as string) ?? string.Empty;
        }

        /// <summary>
        /// Checks whether the VTank macro engine is currently enabled.
        /// </summary>
        /// <returns>
        /// <c>true</c> if macros are active; otherwise <c>false</c>.
        /// </returns>
        public static bool VtMacroEnabled()
        {
            return vTank.Instance.MacroEnabled;
        }

        /// <summary>
        /// Advances VTank to the next waypoint in the current navigation route.
        /// </summary>
        /// <returns>
        /// 1 if the waypoint was advanced successfully; 0 on failure.
        /// </returns>
        public static double VtAdvanceWaypoint()
        {
            try
            {
                var externalInterface = vTank.Instance;
                
                // Basic validation
                if (externalInterface.NavNumPoints == 0)
                {
                    return 0; // No waypoints
                }
                
                int currentWaypoint = externalInterface.NavCurrent;
                int totalWaypoints = externalInterface.NavNumPoints;
                
                // Check if we can advance
                if (currentWaypoint >= totalWaypoints - 1)
                {
                    return 0; // Already at last waypoint
                }
                
                // Check navigation type
                var navType = (int)externalInterface.NavType;
                if (navType == 2 || navType == 4) // Target or Once
                {
                    return 0;
                }
                
                // Access the cExternalInterfaceTrustedRelay and get the PC (PluginCore) reference
                // From decompiled code: external interface uses PC.NavCurrent which references dz.o.l
                var interfaceType = externalInterface.GetType();
                
                // Look for any way to get to the PluginCore instance
                // The interface should have access to PC or some way to reach it
                
                // Try to get the underlying assembly and find the PC static field
                var assembly = interfaceType.Assembly;
                var pluginCoreType = assembly.GetType("uTank2.PluginCore");
                
                if (pluginCoreType != null)
                {
                    // Get the static PC field
                    var pcField = pluginCoreType.GetField("PC", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
                    
                    if (pcField != null)
                    {
                        var pluginCoreInstance = pcField.GetValue(null);
                        
                        if (pluginCoreInstance != null)
                        {
                            // Try to call the advance method 'i' on the PluginCore instance
                            // Need to specify parameter types to avoid "Ambiguous match found"
                            Type[] parameterTypes = new Type[] { typeof(object), assembly.GetType("MetaViewWrappers.MVControlEventArgs") };
                            var advanceMethod = pluginCoreType.GetMethod("i", 
                                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance,
                                null, parameterTypes, null);
                            
                            if (advanceMethod != null)
                            {
                                // Call with parameters matching: i(object A_0, MVControlEventArgs A_1)
                                advanceMethod.Invoke(pluginCoreInstance, new object[] { null, null });
                                return 1;
                            }
                        }
                    }
                    
                    // Fallback: try to access dz static field directly
                    var dzField = pluginCoreType.GetField("dz", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
                    
                    if (dzField != null)
                    {
                        var dzObject = dzField.GetValue(null);
                        
                        if (dzObject != null)
                        {
                            // Navigate the dz.o.l path
                            var dzType = dzObject.GetType();
                            var oField = dzType.GetField("o", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                            
                            if (oField != null)
                            {
                                var oObject = oField.GetValue(dzObject);
                                if (oObject != null)
                                {
                                    var oType = oObject.GetType();
                                    var lField = oType.GetField("l", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                                    
                                    if (lField != null)
                                    {
                                        // Get current value and increment it
                                        int current = (int)lField.GetValue(oObject);
                                        current++;
                                        if (current >= totalWaypoints)
                                        {
                                            current = totalWaypoints - 1;
                                        }
                                        lField.SetValue(oObject, current);
                                        return 1;
                                    }
                                }
                            }
                        }
                    }
                }
                
                return 0;
            }
            catch (System.Exception ex)
            {
                PluginCore.WriteToChat("VTank advance error: " + ex.Message);
                return 0;
            }
        }
    }
}
