using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Tilemaps;

public class Probe : MonoBehaviour
{
	// ********************************************************************************
	// Constants
	public enum GameState
	{
		Ready,
		Playing,
		Win,
		Lose
	}

	public static readonly int ProximityLevels = 1;
	public static readonly float ProximityCollider_Width = 0.12f;
	public static readonly float ProximityCollider_Height = 0.1f;
	public static readonly float ProximityCollider_BaseOffset = 0.08f + (ProximityCollider_Height / 2.0f);

	float TimeAllowed = 40.0f;
	float TimeThreeStars = 20.0f;
	float TimeTwoStars = 10.0f;

	// ********************************************************************************
	// Members
	GameState _gameState;

	Vector3 _startPosition;

	Vector2 _axisMove = Vector2.zero;
	BoxCollider2D[] _proximityCollidersUp = new BoxCollider2D[3];
	BoxCollider2D[] _proximityCollidersDown = new BoxCollider2D[3];
	BoxCollider2D[] _proximityCollidersLeft = new BoxCollider2D[3];
	BoxCollider2D[] _proximityCollidersRight = new BoxCollider2D[3];

	int _proximityUp;
	int _proximityDown;
	int _proximityLeft;
	int _proximityRight;

	// ********************************************************************************
	// Properties
	public BoxCollider2D MainCollider;
	public Rigidbody2D Rigidbody;
	public Tilemap WallTiles;
	public BoxCollider2D GoalCollider;
	public SpriteRenderer StartPointer;
	public Clock Clock;
	public Joe Joe;
	public Help Help;
	public GameObject EndBox;
	public GameObject EndStar1;
	public GameObject EndStar2;
	public GameObject EndStar3;
	public TextMeshProUGUI EndText1;
	public TextMeshProUGUI EndText2;

	public GameState State => _gameState;
	public Vector2 Movement => _axisMove;

	public int ProximityUp => _proximityUp;
	public int ProximityDown => _proximityDown;
	public int ProximityLeft => _proximityLeft;
	public int ProximityRight => _proximityRight;

	// ********************************************************************************
	// Unity messages
	void Start()
	{
		_startPosition = transform.position;

		for (int i = 0; i < ProximityLevels; i++)
		{
			float offset = (ProximityLevels - i - 1) * ProximityCollider_Height;

			_proximityCollidersUp[i] = gameObject.AddComponent<BoxCollider2D>();
			_proximityCollidersUp[i].isTrigger = true;
			_proximityCollidersUp[i].size = new Vector2(ProximityCollider_Width, ProximityCollider_Height);
			_proximityCollidersUp[i].offset = new Vector2(0.0f, ProximityCollider_BaseOffset + offset);

			_proximityCollidersDown[i] = gameObject.AddComponent<BoxCollider2D>();
			_proximityCollidersDown[i].isTrigger = true;
			_proximityCollidersDown[i].size = new Vector2(ProximityCollider_Width, ProximityCollider_Height);
			_proximityCollidersDown[i].offset = new Vector2(0.0f, -ProximityCollider_BaseOffset - offset);

			_proximityCollidersLeft[i] = gameObject.AddComponent<BoxCollider2D>();
			_proximityCollidersLeft[i].isTrigger = true;
			_proximityCollidersLeft[i].size = new Vector2(ProximityCollider_Height, ProximityCollider_Width);
			_proximityCollidersLeft[i].offset = new Vector2(-ProximityCollider_BaseOffset - offset, 0.0f);

			_proximityCollidersRight[i] = gameObject.AddComponent<BoxCollider2D>();
			_proximityCollidersRight[i].isTrigger = true;
			_proximityCollidersRight[i].size = new Vector2(ProximityCollider_Height, ProximityCollider_Width);
			_proximityCollidersRight[i].offset = new Vector2(ProximityCollider_BaseOffset + offset, 0.0f);
		}

		GetComponent<SpriteRenderer>().enabled = false;

		EndBox.SetActive(false);
		Clock.TimeLeft = TimeAllowed;

		_gameState = GameState.Ready;
	}

	void Update()
	{
		_proximityUp = 0;
		_proximityDown = 0;
		_proximityLeft = 0;
		_proximityRight = 0;

		for (int i = 0; i < ProximityLevels; i++)
		{
			if (IsProbeOverlappingWall(_proximityCollidersUp[i])) _proximityUp = (i + 1);
			if (IsProbeOverlappingWall(_proximityCollidersDown[i])) _proximityDown = (i + 1);
			if (IsProbeOverlappingWall(_proximityCollidersLeft[i])) _proximityLeft = (i + 1);
			if (IsProbeOverlappingWall(_proximityCollidersRight[i])) _proximityRight = (i + 1);
		}

		if (_gameState == GameState.Playing)
		{
			if (Clock.TimeLeft <= 0.0f)
			{
				_gameState = GameState.Lose;

				EndText1.text = "You have failed to make the subject LAUGH in the given time period.";
				EndText2.text = "You have been DEMOTED. Enjoy your time mopping the floors of the probing chambers, envying your peers' superiority.\nPress R to try again.";
				EndBox.SetActive(true);
				EndStar1.SetActive(false);
				EndStar2.SetActive(false);
				EndStar3.SetActive(false);
			}
			else if (IsProbeOverlappingGoal())
			{
				var myTime = Mathf.Ceil(Clock.TimeLeft);
				Clock.Running = false;
				Joe.Laugh();

				EndText1.text = "You have successfully made the subject LAUGH!\nYour evaluation is:";
				
				if (myTime >= TimeThreeStars)
				{
					EndText2.text = "You have been promoted to:\nChief Probing Officer\nEnjoy the bonuses.\nPress R to replay.";
					EndBox.SetActive(true);
				}
				else if (myTime >= TimeTwoStars)
				{
					EndText2.text = "You have been promoted to:\nSenior Prober\nHappy hour at 15:00 on fridays. Participation mandatory.\nPress R to try again.";
					EndBox.SetActive(true);
					EndStar1.SetActive(true);
					EndStar2.SetActive(true);
					EndStar3.SetActive(false);
				}
				else
				{
					EndText2.text = "You get to keep your current job. Learn to probe faster, noob.\nPress R to try again.";
					EndBox.SetActive(true);
					EndStar1.SetActive(true);
					EndStar2.SetActive(false);
					EndStar3.SetActive(false);
				}

				_gameState = GameState.Win;				
			}
		}
		else
		{
			Rigidbody.velocity = Vector3.zero;
		}
	}

	void FixedUpdate()
	{
		//Rigidbody.velocity = _axisMove;
		Rigidbody.AddForce(_axisMove);
	}

	// ********************************************************************************
	// Input events
	void OnMove(InputValue value)
	{
		if (Help.IsVisible)
			return;

		if ((_gameState == GameState.Win) || (_gameState == GameState.Lose))
			return;

		Joe.StartProbing();
		_axisMove = value.Get<Vector2>();
		Clock.Running = true;
		StartPointer.enabled = false;

		_gameState = GameState.Playing;
	}

	void OnRestart()
	{
		if (Help.IsVisible)
			return;

		Rigidbody.velocity = Vector3.zero;
		transform.position = _startPosition;
		EndBox.SetActive(false);
		Clock.Running = false;
		Clock.TimeLeft = TimeAllowed;
		StartPointer.enabled = true;
		Joe.Reset();

		_gameState = GameState.Ready;
	}

	// ********************************************************************************
	// Tools
	bool IsProbeOverlappingWall(Collider2D collider)
	{
		List<Collider2D> results = new();

		if (collider.OverlapCollider(new ContactFilter2D(), results) != 0)
		{
			foreach (var result in results)
			{
				if (result.gameObject == WallTiles.gameObject)
					return true;
			}
		}

		return false;
	}

	bool IsProbeOverlappingGoal()
	{
		return MainCollider.IsTouching(GoalCollider);

		//List<Collider2D> results = new();
		//
		//if (MainCollider.OverlapCollider(new ContactFilter2D(), results) != 0)
		//{
		//	foreach (var result in results)
		//	{
		//		if (result.GetComponent<GoalPoint>() != null)
		//			return true;
		//	}
		//}
		//
		//return false;
	}
}
