using System;
using System.Runtime.CompilerServices;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using MoreSlugcats;
using RWCustom;
using UnityEngine;
using static AbstractPhysicalObject;

namespace JilloSlug;

// fisobs? never heard of them

public static class JilloSlimeMold {
    private static ConditionalWeakTable<AbstractPhysicalObject, StrongBox<bool>> JilloMolds = new ConditionalWeakTable<AbstractPhysicalObject, StrongBox<bool>>();

    public static bool IsJilloSlimeMold(AbstractPhysicalObject mold) {
        return JilloMolds.TryGetValue(mold, out var isJillo) && isJillo.Value;
    }
    public static bool IsJilloSlimeMold(PhysicalObject mold) {
        return IsJilloSlimeMold(mold.abstractPhysicalObject);
    }

    public static void SetJilloSlimeMold(AbstractPhysicalObject mold, bool value = true) {
        JilloMolds.Add(mold, new StrongBox<bool>(value));
    }
    public static void SetJilloSlimeMold(PhysicalObject mold, bool value = true) {
        SetJilloSlimeMold(mold.abstractPhysicalObject, value);
    }

    public static void AddHooks() {
        On.SlimeMold.ApplyPalette += SlimeMold_ApplyPalette;
        On.Player.TossObject += Player_TossObject;
    }

    private static void SlimeMold_ApplyPalette(On.SlimeMold.orig_ApplyPalette orig, SlimeMold self, RoomCamera.SpriteLeaser sLeaser, RoomCamera rCam, RoomPalette palette) {
        if (!IsJilloSlimeMold(self)) {
            orig(self, sLeaser, rCam, palette);
            return;
        }
        self.darkMode = Mathf.InverseLerp(0.3f, 0.9f, palette.darkness);
        self.color = SlimeMoldColorFromPalette(palette);
    }

    private static Color SlimeMoldColorFromPalette(RoomPalette palette) {
        Color col = Color.Lerp(
            Custom.HSL2RGB(Mathf.Lerp(0.05f, 0.045f, palette.darkness), 0.59f, 0.63f),
            palette.fogColor,
            Mathf.Lerp(0.15f, 0.25f, palette.fogAmount) * Mathf.Lerp(0.1f, 0.5f, palette.darkness)
        );
        col.a = 0.7f;
        return col;
    }

    private static void Player_TossObject(On.Player.orig_TossObject orig, Player self, int grasp, bool eu) {
        if (self.grasps[grasp] != null && IsJilloSlimeMold(self.grasps[grasp].grabbed)) {
            PhysicalObject grabbed = self.grasps[grasp].grabbed;

			IntVector2 throwDir = new IntVector2(self.ThrowDirection, 0);
			bool throwVertical = self.input[0].y < 0;
			if (ModManager.MMF && MMF.cfgUpwardsSpearThrow.Value) {
				throwVertical = self.input[0].y != 0;
			}
			if (self.animation == Player.AnimationIndex.Flip && throwVertical && self.input[0].x == 0) {
				throwDir = new IntVector2(0, (ModManager.MMF && MMF.cfgUpwardsSpearThrow.Value) ? self.input[0].y : (-1));
			}
			if (ModManager.MMF && self.bodyMode == Player.BodyModeIndex.ZeroG && MMF.cfgUpwardsSpearThrow.Value) {
				int y = self.input[0].y;
				throwDir = ((y == 0) ? new IntVector2(self.ThrowDirection, 0) : new IntVector2(0, y));
			}
			Vector2 thrownPos = self.firstChunk.pos + throwDir.ToVector2() * 10f + new Vector2(0f, 4f);
			if (self.room.GetTile(thrownPos).Solid) {
				thrownPos = self.mainBodyChunk.pos;
			}

            self.room.PlaySound(SoundID.Slugcat_Throw_Misc_Inanimate, self.grasps[grasp].grabbedChunk, loop: false, 1f, 1f);
            //(grabbed as Weapon).Thrown(self, thrownPos, self.mainBodyChunk.pos - throwDir.ToVector2() * 10f, throwDir, Mathf.Lerp(1f, 1.5f, self.Adrenaline), eu);

			for (int l = 0; l < grabbed.bodyChunks.Length; l++) {
				grabbed.bodyChunks[l].vel = Vector2.Lerp(grabbed.bodyChunks[l].vel * 0.35f, self.mainBodyChunk.vel, Custom.LerpMap(grabbed.TotalMass, 0.2f, 0.5f, 0.6f, 0.3f));
				grabbed.bodyChunks[l].vel += throwDir.ToVector2() * 40f * Mathf.Lerp(1f, 1.5f, self.Adrenaline);
                if (throwDir.x != 0) {
                    self.firstChunk.vel.y += 1.5f;
                }
            }

			if (self.animation == Player.AnimationIndex.ClimbOnBeam && ModManager.MMF && MMF.cfgClimbingGrip.Value) {
				self.bodyChunks[0].vel += throwDir.ToVector2() * 2f;
				self.bodyChunks[1].vel -= throwDir.ToVector2() * 8f;
			} else {
				self.bodyChunks[0].vel += throwDir.ToVector2() * 8f;
				self.bodyChunks[1].vel -= throwDir.ToVector2() * 4f;
			}

			if (self.graphicsModule != null) (self.graphicsModule as PlayerGraphics).ThrowObject(grasp, grabbed);

			self.Blink(15);

            self.dontGrabStuff = (self.isNPC ? 45 : 15);

            if (self.graphicsModule != null) (self.graphicsModule as PlayerGraphics).LookAtObject(grabbed);

            if (grabbed is PlayerCarryableItem) {
                (grabbed as PlayerCarryableItem).Forbid();
            }

            self.ReleaseGrasp(grasp);
        } else {
            orig(self, grasp, eu);
        }
    }
}
