using Celeste.Mod.LakeSideCode.FishDefs;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Monocle;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Celeste.Mod.LakeSideCode.Entities {
	public class FishingHUD : Entity {

		private static readonly float LerpTime = 0.3f;
		private static readonly float Scale = 6f;

		private static float BGScale => Scale * 0.3f;
		private static float ScreenPadding => 16f * Scale + 16f;
		private bool ShowInventory => LakeSideCodeModule.Session.Inventory != FishType.Nothing;
		private bool RenderInventory => inventoryLerp > 0;
		private bool ShowTracker => LakeSideCodeModule.Session?.HasFishingRod == true;
		private bool RenderTracker => trackerLerp > 0;

		private VirtualRenderTarget rendTarget;
		private float inventoryLerp = 0f;
		private float trackerLerp = 0f;
		private FishType inventoryFishType = FishType.Nothing;

		internal bool struggling = false;
		internal float struggleFishMovementControl = 0f;
		internal float struggleProgress = 0f;
		internal float strugglePos = 0.5f;
		internal float struggleFishPos = 0.5f;
		internal float struggleMovement = 0f;
		internal float struggleLeniency = 0.1f;
		internal FishType struggleFishType = FishType.Bass;

		private MTexture struggleBgTex;
		private MTexture struggleOutlineTex;
		private MTexture struggleSliderTex;
		private MTexture inventoryIndicatorTex;

		public FishingHUD() : base() {
			Tag = Tags.HUD | Tags.Global;
			Add(new BeforeRenderHook(BeforeRender));
			struggleBgTex = GFX.Gui["Phobscodestuff/Lakesidecodestuff/strugglebar_interior"];
			struggleOutlineTex = GFX.Gui["Phobscodestuff/Lakesidecodestuff/strugglebar_outline"];
			struggleSliderTex = GFX.Gui["Phobscodestuff/Lakesidecodestuff/strugglebar_slider"];
			inventoryIndicatorTex = GFX.Gui["Phobscodestuff/Lakesidecodestuff/inventory_indicator"];
		}

		public override void Update() {
			base.Update();
			if (LakeSideCodeModule.Session?.HasFishingRod == false) return;
			inventoryLerp = Calc.Approach(inventoryLerp, ShowInventory ? 1 : 0, Engine.DeltaTime / LerpTime);
			trackerLerp = Calc.Approach(trackerLerp, ShowTracker ? 1 : 0, Engine.DeltaTime / LerpTime);
			// if ((LakeSideCodeModule.Session?.Inventory ?? FishType.Nothing) != FishType.Nothing) {
				inventoryFishType = LakeSideCodeModule.Session.Inventory;
			// }
		}

		public void BeforeRender() {
			if (LakeSideCodeModule.Session?.HasFishingRod == false) return;
			rendTarget ??= VirtualContent.CreateRenderTarget("lakeside-inventory-target", 1920, 1080);
			Engine.Graphics.GraphicsDevice.SetRenderTarget(rendTarget);
			Engine.Graphics.GraphicsDevice.Clear(Color.Transparent);
			StartSpriteBatch();
			DrawTracker();
			EndSpriteBatch();
			StartSpriteBatch();
			DrawStruggleUI();
			EndSpriteBatch();
		}

		private static void StartSpriteBatch() {
			Draw.SpriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend,
				SamplerState.PointWrap, DepthStencilState.None, RasterizerState.CullNone);
		}

		private static void EndSpriteBatch() {
			Draw.SpriteBatch.End();
		}

		private void DrawTracker() {
			if (!RenderTracker) return;
			List<FishType> list = [
				FishType.Bass,
				FishType.Trout,
				FishType.Spring,
				FishType.Stone,
				FishType.StoneEater,
				FishType.Blahaj,
				FishType.Bomb,
				FishType.Leaf,
				FishType.Angel,
				FishType.Devil,
				FishType.Cooked,
				FishType.Mythic,
			];
			const float imageSize = 72f;
			const float padding = 10f;
			const float btnWidth = 32f;
			const float textScale = 0.5f;

			float xPos = 960 - (list.Count - 1) * (imageSize + padding) * 0.5f;
			if (inventoryFishType == FishType.Coin) {
				list.Add(FishType.Coin);
			}
			foreach (FishType type in list) {
				MTexture tex = GFX.Game[FishTypeUtil.TexPath(type)];
				Color color = (type == FishType.Coin || LakeSideCodeModule.Session?.CatchCounter.ContainsKey(type) == true) ? Color.White : Color.Black;

				
				if(LakeSideCodeModule.Session.FishDiscoveryFish == type) {
					if(LakeSideCodeModule.Session.FishDiscoveryFish == FishType.Coin) {
						color = Color.Lerp(Color.Transparent, Color.White, LakeSideCodeModule.Session.FishDiscoveryFade);
					} else {
						color = Color.Lerp(Color.Black, Color.White, LakeSideCodeModule.Session.FishDiscoveryFade);
					}
				}

				if (type == inventoryFishType) {
					Vector2 invPos = new(xPos, Calc.LerpClamp(-imageSize, imageSize, Ease.CubeOut(inventoryLerp)));
					inventoryIndicatorTex.DrawCentered(invPos);
					if (inventoryFishType == LakeSideCodeModule.Session?.Inventory) {
						var virtButton = BirdTutorialGui.ButtonPromptToVirtualButton(BirdTutorialGui.ButtonPrompt.Grab);
						MTexture button = Input.GuiButton(virtButton, "controls/keyboard/oemquestion");
						float btnScale = btnWidth / button.Width;
						string text = Dialog.Clean("LAKESIDE_GUI_THROW");
						float totalWidth = btnWidth + ActiveFont.Measure(text).X * textScale;
						button.DrawJustified(new(xPos - totalWidth * 0.5f, imageSize * 2), new(0f, 0.5f), Color.White, btnScale);
						ActiveFont.Draw(text, new(xPos - totalWidth * 0.5f + btnWidth, imageSize * 2), new(0f, 0.5f), Vector2.One * textScale, Color.White);
					}
				}
				tex.DrawCentered(new(xPos, imageSize), color, imageSize / tex.Width);
				xPos += imageSize + padding;
			}
		}

		private void DrawStruggleUI() {
			if (!struggling) return;
			Player p = Scene.Tracker.GetEntity<Player>();
			Vector2 ppos = p == null ? Vector2.Zero : SceneAs<Level>().Camera.CameraToScreen(p.Position) * 6f;

			bool onTarget = MathF.Abs(strugglePos - struggleFishPos) < struggleLeniency;
			Color playerColor = onTarget ? Color.LightGreen : Color.Gray;
			Color borderColor = Color.Lerp(Color.White, Color.LightGreen, struggleProgress);
			Color bgColor = struggleProgress >= 1f ? Color.Green : Color.White;
			MTexture fishTex = GFX.Game[FishTypeUtil.TexPath(struggleFishType)];
			int subtexHeight = (int)MathF.Round(struggleProgress * fishTex.Height);
			MTexture fishTexVisible = fishTex.GetSubtexture(0, fishTex.Height - subtexHeight, fishTex.Width, subtexHeight);
			//MTexture bobber = GFX.Game["objects/Phobscodestuff/Lakesidecodestuff/bobber"];

			Vector2 barCenter = ppos + (ppos.Y < 500 ? new(0f, 100f) : new(0f, -250));
			barCenter.X = Calc.Clamp(barCenter.X, struggleBgTex.Width / 2f * Scale + 100f, 1820 - struggleBgTex.Width / 2f * Scale);
			float slideMinX = barCenter.X - (struggleBgTex.Width - struggleSliderTex.Width) / 2.0f * Scale;
			float slideMaxX = barCenter.X + (struggleBgTex.Width - struggleSliderTex.Width) / 2.0f * Scale;
			Vector2 sliderPos = new(Calc.LerpClamp(slideMinX, slideMaxX, strugglePos), barCenter.Y);
			Vector2 fishPos = new(Calc.LerpClamp(slideMinX, slideMaxX, struggleFishPos), barCenter.Y + fishTex.Height * Scale * 0.375f);
			//Vector2 overlayPos = fishPos + Vector2.UnitY * ((1 - struggleProgress) * 300f);

			struggleBgTex.DrawCentered(barCenter, bgColor, Scale);
			struggleSliderTex.DrawCentered(sliderPos, playerColor, Scale);
			struggleOutlineTex.DrawCentered(barCenter, borderColor, Scale);
			fishTex.DrawJustified(fishPos, new(.5f, 1f), Color.Black, Scale * 0.75f);
			fishTexVisible.DrawJustified(fishPos, new(.5f, 1f), Color.White, Scale * 0.75f);
			//Draw.Line(overlayPos, barCenter - Vector2.UnitY * 300, Color.Black, 8f);
			//Draw.Line(overlayPos, barCenter - Vector2.UnitY * 300, Color.LightGray, 4f);
			//fishTex.DrawCentered(overlayPos, Color.White, Scale * 0.75f);

	
			MTexture leftButton = Input.GuiDirection(new Vector2(-1, 0));
			MTexture rightButton = Input.GuiDirection(new Vector2(1, 0));
			Vector2 offset = new Vector2(Scale * struggleBgTex.Width / 2 + leftButton.Width / 2, 0);

			Color dimColor = Color.Gray;

			leftButton.DrawCentered(barCenter - offset, Input.MoveX >= 0 ? dimColor : Color.White, 1);
			rightButton.DrawCentered(barCenter + offset, Input.MoveX <= 0 ? dimColor : Color.White, 1);
		}

		public override void Render() {
			base.Render();
			if (LakeSideCodeModule.Session?.HasFishingRod == false) return;
			if (rendTarget != null) {
				Color color = (SceneAs<Level>()?.Paused == true) ? Color.DarkGray * 0.4f : Color.White;
				Draw.SpriteBatch.Draw(rendTarget, Vector2.Zero, color);
			}
		}

	}
}
