using System.Diagnostics.CodeAnalysis;
#if HARMONY_2
using System;
using HarmonyLib;
#else
using System.Reflection;
using Harmony;
#endif
using StardewModdingAPI.Framework.Patching;
using StardewValley;
namespace StardewModdingAPI.Mods.ErrorHandler.Patches
{
    /// A Harmony patch for  which intercepts invalid preconditions and logs an error instead of crashing.
    /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments.
    [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
    [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")]
    internal class GameLocationPatches : IHarmonyPatch
    {
        /*********
        ** Fields
        *********/
        /// Writes messages to the console and log file on behalf of the game.
        private static IMonitor MonitorForGame;
        /*********
        ** Public methods
        *********/
        /// Construct an instance.
        /// Writes messages to the console and log file on behalf of the game.
        public GameLocationPatches(IMonitor monitorForGame)
        {
            GameLocationPatches.MonitorForGame = monitorForGame;
        }
        /// 
#if HARMONY_2
        public void Apply(Harmony harmony)
        {
            harmony.Patch(
                original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"),
                finalizer: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Finalize_GameLocation_CheckEventPrecondition))
            );
        }
#else
        public void Apply(HarmonyInstance harmony)
        {
            harmony.Patch(
                original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"),
                prefix: new HarmonyMethod(this.GetType(), nameof(GameLocationPatches.Before_GameLocation_CheckEventPrecondition))
            );
        }
#endif
        /*********
        ** Private methods
        *********/
#if HARMONY_2
        /// The method to call instead of GameLocation.checkEventPrecondition.
        /// The return value of the original method.
        /// The precondition to be parsed.
        /// The exception thrown by the wrapped method, if any.
        /// Returns the exception to throw, if any.
        private static Exception Finalize_GameLocation_CheckEventPrecondition(ref int __result, string precondition, Exception __exception)
        {
            if (__exception != null)
            {
                __result = -1;
                EventErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{__exception.InnerException}", LogLevel.Error);
            }
            return null;
        }
#else
        /// The method to call instead of GameLocation.checkEventPrecondition.
        /// The instance being patched.
        /// The return value of the original method.
        /// The precondition to be parsed.
        /// The method being wrapped.
        /// Returns whether to execute the original method.
        private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod)
        {
            const string key = nameof(GameLocationPatches.Before_GameLocation_CheckEventPrecondition);
            if (!PatchHelper.StartIntercept(key))
                return true;
            try
            {
                __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition });
                return false;
            }
            catch (TargetInvocationException ex)
            {
                __result = -1;
                GameLocationPatches.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error);
                return false;
            }
            finally
            {
                PatchHelper.StopIntercept(key);
            }
        }
#endif
    }
}