using UnityEngine;

namespace ScrambleKit.Move
{
    [RequireComponent(typeof(MoveInputSource))]
    public class MoveCore : MonoBehaviour
    {
        public LayerMask WalkOnLayers = ~0;  // ~0 means "all layers"
        public float GroundCheckProbeLen = 0.8f;

        public MoveInputSource input { get; private set; }
        public Rigidbody2D rb2 { get; private set; }
        public Collider2D c2 { get; private set; }

        private string animState;
        private Animator anim;

        private Vector3 origScale;
        private float lastGroundedTime;

        void Awake()  // not Start b/c of weird order in instantiated prefabs described here: https://forum.unity.com/threads/start-before-update-except-when.32070/
        {
            origScale = transform.localScale;
            input = GetComponent<MoveInputSource>();
            rb2 = GetComponent<Rigidbody2D>();
            c2 = gameObject.GetComponent<Collider2D>();
            anim = gameObject.GetComponent<Animator>();            
            Animate("Idle");
        }

        public void Animate(string stateName)
        {
            if (anim == null || animState == stateName)
                return;

            animState = stateName;
            anim.Play(animState);
        }

        public void FaceXDirection(float face)
        {
            float factor = (face >= 0) ? 1 : -1;
            transform.localScale = new Vector3(origScale.x * factor, origScale.y, origScale.z);
        }

        public bool IsTouchingGround()
        {
            Vector2 ctr = c2.bounds.center;
            float checkWidth = 0.999f;  // ensures ray originates inside player, saw bugginess checking exactly at collider edge
            Vector2 left = ctr + new Vector2(-c2.bounds.extents.x * checkWidth, 0);
            Vector2 right = ctr + new Vector2(c2.bounds.extents.x * checkWidth, 0);

            RaycastHit2D res1 = Physics2D.Raycast(left, -Vector2.up, GroundCheckProbeLen, WalkOnLayers);
            RaycastHit2D res2 = Physics2D.Raycast(ctr, -Vector2.up, GroundCheckProbeLen, WalkOnLayers);
            RaycastHit2D res3 = Physics2D.Raycast(right, -Vector2.up, GroundCheckProbeLen, WalkOnLayers);

            Debug.DrawLine(left, left - Vector2.up * GroundCheckProbeLen);
            Debug.DrawLine(ctr, ctr - Vector2.up * GroundCheckProbeLen);
            Debug.DrawLine(right, right - Vector2.up * GroundCheckProbeLen);

            bool grounded = (res1.collider != null) || (res2.collider != null) || (res3.collider != null);
            if (grounded)
                lastGroundedTime = Time.fixedTime;
            return grounded;
        }

        public bool RecentlyTouchedGround(float leewayTime)
        {
            return IsTouchingGround() || (Time.fixedTime - lastGroundedTime <= leewayTime);
        }
    }
}