using Godot;
using System;
using System.Collections.Generic;

public partial class Player : CharacterBody2D
{
	private const double TransitionTime = 0.5;
	private const double CameraTransitionTime = 0.25;
	public enum State
	{
		Normal,
		Transition,
		ReadChat
	}

	private State _state;
	
	[Export] public State CurrentState
	{
		get => _state;
		private set
		{
			_state = value;
			switch (_state)
			{
				case State.Normal:
					Visible = true;
					break;
				case State.Transition:
					Visible = false;
					break;
				case State.ReadChat:
					// ChatLog.Visible = !ChatLog.Visible;
					break;
				default:
					throw new ArgumentOutOfRangeException();
			}
		}
	}
	
	[Export] public float Speed = 300.0f;

	// Get the gravity from the project settings to be synced with RigidBody nodes.
	public float Gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();
	
	public List<Node2D> InteractableObjects = new List<Node2D>();

	public Node2D InteractableObject
	{
		get
		{
			if (InteractableObjects.Count == 0) return null;
			var nearObj = InteractableObjects[0];
			var minDistance = (GlobalPosition - nearObj.GlobalPosition).Length();
			foreach (var obj in InteractableObjects)
			{
				var distance = (GlobalPosition - obj.GlobalPosition).Length();
				if (minDistance > distance)
				{
					minDistance = distance;
					nearObj = obj;
				}
			}

			return nearObj;
		}
	}
	
	protected AnimatedSprite2D Sprite;
	protected PanelContainer ChatLog;
	protected Camera2D Camera;
	protected AudioCollection Footsteps;

	private Vector2 _newPosition;
	private double _currentTransitionTime = 0;
	private double _currentCameraTransitionTime = 0;
	private Vector2 _previousPosition;
	private Vector2 _nextPosition;
	private Vector2 _cameraDefaultPosition = new(0, -20);
	private Vector2 _cameraChatLogPosition = new(116, -20);
	public override void _Ready()
	{
		Sprite = (AnimatedSprite2D)FindChild("AnimatedSprite2D");
		ChatLog = (PanelContainer)FindChild("ChatLog");
		Camera = (Camera2D)FindChild("Camera2D");
		Footsteps = (AudioCollection)FindChild("Footsteps");
	}

	public override void _PhysicsProcess(double delta)
	{
		switch (CurrentState)
		{
			case State.Normal:
				
				if (Camera.Offset != _cameraDefaultPosition)
				{
					if (_currentCameraTransitionTime < CameraTransitionTime)
					{
						Camera.Offset = _cameraChatLogPosition.Lerp(_cameraDefaultPosition, (float)(_currentCameraTransitionTime * 1/CameraTransitionTime));
						_currentCameraTransitionTime += delta;
					}
					else
					{
						_currentCameraTransitionTime = 0;
					}
				}
				
				Vector2 velocity = Velocity;

				// if (!IsOnFloor())
				// {
				// 	velocity += GetGravity() * (float)delta;
				// }
				//
				// if (IsOnFloor() && !Visible)
				// {
				// 	Visible = true;
				// }
				
				Vector2 direction = Input.GetVector("move_left", "move_right", "move_up", "move_down");
				if (direction != Vector2.Zero)
				{
					Footsteps.Play();
					// if (!Footsteps.IsPlaying())
					// {
					// 	// Footsteps.PitchScale = (float)GD.RandRange(0.5, 1.0);
					// 	Footsteps.Play();
					// }
					velocity.X = direction.X * Speed;
					Sprite.Play("walk");
					Sprite.FlipH = direction.X switch
					{
						> 0 => false,
						< 0 => true,
						_ => Sprite.FlipH
					};
				}
				else
				{
					// Footsteps.Stop();
					velocity.X = Mathf.MoveToward(Velocity.X, 0, Speed);
					Sprite.Play("default");
				}
	
				Velocity = velocity;
				MoveAndSlide();
				break;
			case State.Transition:
				if (_currentTransitionTime < TransitionTime)
				{
					GlobalPosition = _previousPosition.Lerp(_nextPosition, (float)(_currentTransitionTime * 1/TransitionTime));
					_currentTransitionTime += delta;
				}
				else
				{
					_currentTransitionTime = 0;
					CurrentState = State.Normal;
				}

				break;
			case State.ReadChat:
				if (Camera.Offset != _cameraChatLogPosition)
				{
					if (_currentCameraTransitionTime < CameraTransitionTime)
					{
						Camera.Offset = _cameraDefaultPosition.Lerp(_cameraChatLogPosition, (float)(_currentCameraTransitionTime * 1/CameraTransitionTime));
						_currentCameraTransitionTime += delta;
					}
					else
					{
						_currentCameraTransitionTime = 0;
					}
				}
				break;
			default:
				throw new ArgumentOutOfRangeException();
		}
		
	}

	public override void _Input(InputEvent @event)
	{
		if (@event.IsActionPressed("Interact"))
		{
			if (InteractableObject is NPC npc)
			{
				npc.test();
			}

			if (InteractableObject is Door door)
			{
				_previousPosition = GlobalPosition;
				_nextPosition = door.Exit.GlobalPosition;
				CurrentState = State.Transition;
			}
		}

		if (@event.IsActionPressed("show_chat"))
		{
			switch (CurrentState)
			{
				case State.Normal:
					CurrentState = State.ReadChat;
					break;
				case State.ReadChat:
					CurrentState = State.Normal;
					break;
			}
		}
	}
}
