using UnityEngine;
using System.Collections;

namespace CharacterEngine.Primitives
{
    public struct CECollision
    {
        public Vector2 impulse;
        public Vector2 point;
        public Vector2 normal;

        /// <summary>
        /// RESOLVE THE COLLISION AND RETURN A COLLISION VALUE
        /// a = Collider wich is dynamic 
        /// b = static Collider
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        public static CECollision ResolveCollision (CECollider a, CECollider b)
        {
            Vector2 closestPoint = Vector2.zero;
            CECollision collision = new CECollision();

            ///IS NOT MTV THO (music television) is MINIMUN TRANSLATION VECTOR (funny joke uh)
            Vector2 MTV = Vector2.zero;
            float minimunOverlap = 0.0f;

            Vector2[] axes = new Vector2[8];

            for (int i = 0; i < 8; i++)
            {
                axes[i] = i < 4 ? a.GetNormal(i) : b.GetNormal(i - 4);
            }

            for (int i = 0; i < axes.Length; i++)
            {
                CEProjection projectionA = new CEProjection(a, axes[i]);
                CEProjection projectionB = new CEProjection(b, axes[i]);

                float overlapValue = Mathf.Abs(projectionA.max - projectionB.min);

                if (i == 0 || overlapValue < minimunOverlap)
                {
                    minimunOverlap = overlapValue;
                    MTV = axes[i] * minimunOverlap;
                }
            }

            collision.impulse = MTV;
            collision.normal = collision.impulse.normalized;
            ///COULDNT DETRMINE YET HOW TO FIND POINT ILL DO IT ASFASDGSD
            collision.point = Vector2.zero;
            /*
            for (int i = 0; i < 4; i++)
            {
                Vector2 currentPoint = a.GetPoint(i);
                if (b.ContainsPoint(currentPoint))
                {
                    closestPoint = ClosestPointInBounds(b, currentPoint);

                    collision.impulse = closestPoint - currentPoint;
                    collision.normal = collision.impulse.normalized;
                    collision.point = closestPoint;

                    return collision;
                }
            }

            for (int i = 0; i < 4; i++)
            {
                Vector2 currentPoint = b.GetPoint(i);
                if (a.ContainsPoint(currentPoint))
                {
                    closestPoint = ClosestPointInBounds(a, currentPoint);

                    collision.impulse = (closestPoint - currentPoint) * -1;
                    collision.normal = collision.impulse.normalized;
                    collision.point = closestPoint;

                    return collision;
                }
            }
            */

            //IF REACH HERE DIDNT RESOLVE SHIT
            //Debug.Log("Could not resolve collision");
            return collision;
        }

        /// <summary>
        /// GET CLOSEST CONTACT POINT
        /// </summary>
        /// <param name="coll"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static Vector2 ClosestPointInBounds (CECollider coll, Vector2 point)
        {
            Vector2 smallerDelta = Vector2.zero;
            for (int i = 0; i < 4; i++)
            {
                Vector2 cpis = ClosestVectorToSegment(point, coll.GetPoint(CECollider.edges[i, 0]), coll.GetPoint(CECollider.edges[i, 1]));
                Vector2 delta = cpis - point;

                if (smallerDelta == Vector2.zero) smallerDelta = delta;
                else
                {
                    if (delta.sqrMagnitude < smallerDelta.sqrMagnitude)
                        smallerDelta = delta;
                }
            }

            return point + smallerDelta;
        }

        public static Vector2 ClosestVectorToSegment (Vector2 p, Vector2 a, Vector2 b)
        {
            Vector2 segmentNormal = Vector3.Cross((a- b).normalized, Vector3.forward);
            Vector2 distanceToPointA = a - p;
            Vector2 distanceToPointB = b - p;

            return p + (Vector2)Vector3.Project(distanceToPointA, segmentNormal);
        }
        public static Vector2 ClosestVectorToPlane(Vector2 p, Vector2 normal, Vector2 position)
        {
            Vector2 plane = Vector3.Cross(normal, Vector3.forward);
            Vector2 distanceToPosition = position - p;

            return p + (Vector2)Vector3.Project(distanceToPosition, plane);
        }
    }
}
