using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;

[RequireComponent(typeof(GravityBody))]
public class FirstPersonController : MonoBehaviour
{
    public static FirstPersonController Instance;

    public LayerMask GroundedMask;
    public float MaxEnergy { get; private set; }
    public float CurrentEnergy;
    public GravityBody GravityBody;

    private float _walkSpeed = 12f;
    private float _jumpForce = 15f;

    private bool _isGrounded;
    private Vector3 _moveAmount;
    private Vector3 _rotationAmount;
    private Vector3 _smoothMoveVelocity;
    private Rigidbody _rigidbody;

    public Dictionary<string, bool> PlanetsVisited = new Dictionary<string, bool>();
    private int PlanetsToVisit = 25;

    public float Progress
    {
        get
        {
            return Mathf.InverseLerp(0, PlanetsToVisit, PlanetsVisited.Count);
        }
    }


    private bool CanPropell
    {
        get
        {
            return (CurrentEnergy > 0);
        }
    }

    private void Awake()
    {
        Instance = this;
        MaxEnergy = 5f;
        _rigidbody = GetComponent<Rigidbody>();
        GravityBody = GetComponent<GravityBody>();
        GravityBody.OnGravityAttractorChanged += OnGravityChanged;
    }

    private void OnGravityChanged(GravityAttractor newGravity)
    {
    }

    private void Update()
    {
        float inputY = Input.GetAxisRaw("Vertical");

        Vector3 moveDir = new Vector3(0, 0, inputY).normalized;
        Vector3 targetMoveAmount = moveDir * _walkSpeed;
        _moveAmount = Vector3.SmoothDamp(_moveAmount, targetMoveAmount, ref _smoothMoveVelocity, .15f);

        if (_isGrounded && inputY != 0)
        {
            CurrentEnergy += Time.deltaTime;
            CurrentEnergy = Mathf.Min(CurrentEnergy, MaxEnergy);
        }

        // Jump
        if (Input.GetKey(KeyCode.Space) && CanPropell)
        {
            CurrentEnergy -= Time.deltaTime;
            var dir = transform.position - GravityBody.CurrentPlanet.transform.position;
            _rigidbody.AddForce(dir.normalized * _jumpForce);

        }

        // Grounded check
        Ray ray = new Ray(transform.position, -transform.up);
        RaycastHit hit;

        if (Physics.Raycast(ray, out hit, 1 + .1f, GroundedMask))
        {
            _isGrounded = true;
            if (!PlanetsVisited.ContainsKey(GravityBody.CurrentPlanet.name))
            {
                PlanetsVisited.Add(GravityBody.CurrentPlanet.name, true);
                CheckIfGameOver();
            }
        }
        else
        {
            _isGrounded = false;
        }

    }

    private void FixedUpdate()
    {
        Vector3 localMove = transform.TransformDirection(_moveAmount) * Time.fixedDeltaTime;
        _rigidbody.MovePosition(_rigidbody.position + localMove);
        
        transform.Rotate(_rotationAmount, Space.Self);
        GravityBody.CurrentPlanet.Attract(_rigidbody);
    }

    private void CheckIfGameOver()
    {
        if (Progress == 1)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var item in PlanetsVisited.Keys)
            {
                sb.Append(item);
                sb.Append(",");
            }

            PlayerPrefs.SetString("LastResult", sb.ToString());
            SceneManager.LoadScene("EndOfGame");
        }
    }
}
