using Intrepid.Core.Entities;
using Intrepid.Core.Grounding;
using Intrepid.GameManagers;
using Intrepid.Gameplay.Entities.Player.Sentinel.Events;
using Intrepid.Gameplay.Flooring;
using Intrepid.Gameplay.Messages.Events;
using Intrepid.Utilities;
using UnityEngine;

namespace Intrepid.Gameplay.Entities.Player.Sentinel
{
    public class SentinelEntity : Entity
    {
        [GroupInjections, SerializeField] private Rigidbody unityRigidbody;
        [GroupInjections, SerializeField] private CapsuleCollider capsuleCollider;
        [GroupInjections, SerializeField] private Transform modelTransform;
        [GroupInjections, SerializeField] private EntityModelAnimation modelAnimation;
        [GroupInjections, SerializeField] private FloorDetection floorDetection;
        [GroupInjections, SerializeField] private EntityMotorSmoothRotation motorSmoothRotation;
        [GroupInjections, SerializeField] private EntityMotorPhysicsContact motorPhysicsContact;
        [GroupInjections, SerializeField] private EntityMotorTopDown motorTopDown;
        
        private Vector3 _desiredForward = Vector3.forward;
        private Vector3 _intendedDesiredVelocity = Vector3.zero;
        
        protected SentinelBrain Brain => EntityBrain as SentinelBrain;
        private Rigidbody UnityRigidbody => unityRigidbody;
        private CapsuleCollider CapsuleCollider => capsuleCollider;
        // private EntityMotorSmoothRotation MotorSmoothRotation => motorSmoothRotation;
        private EntityMotorPhysicsContact MotorPhysicsContact => motorPhysicsContact;
        private EntityMotorTopDown MotorTopDown => motorTopDown;
        
        public Transform RigidBodyTransform => unityRigidbody.transform;
        public EntityModelAnimation ModelAnimation => modelAnimation;
        public Vector2 DesiredVelocity { get; set; }
        public Vector3 LinearVelocity { get; private set; }
        public Vector2 Forward => new Vector2(_desiredForward.x, _desiredForward.z).normalized;
        public bool IsGrounded => MotorTopDown.IsGrounded;
        public GroundProfiles CurrentGroundProfiles => MotorTopDown.CurrentGroundProfiles;
        public FloorDetection FloorDetection => floorDetection;
        public Vector3 Position
        {
            get => UnityRigidbody.position;
            set => UnityRigidbody.position = value;
        }

        public override void DeployEntity(Vector3 position, Vector2 direction)
        {
            Position = position;
            ChangeOrientation(direction);
            
            UnityRigidbody.isKinematic = false;
            CapsuleCollider.enabled = true;
            MotorTopDown.enabled = true;
            MotorPhysicsContact.enabled = true;
            
            RefreshMovementNormal();
        }

        public override void RetreatEntity()
        {
            UnityRigidbody.isKinematic = true;
            CapsuleCollider.enabled = false;
            MotorTopDown.enabled = false;
            MotorPhysicsContact.enabled = false;
        }

        public void ChangeOrientation(Vector2 direction)
        {
            if (direction.sqrMagnitude <= GonConstants.CommonZeroSqrt)
            {
                return;
            }
            
            _desiredForward.x = direction.x;
            _desiredForward.y = 0;
            _desiredForward.z = direction.y;
            _desiredForward = _desiredForward.normalized;
        }
        
        public override void UpdateFromUpdatable()
        {
            if (!Brain.IsEnabled) return;
            
            modelTransform.rotation = Quaternion.LookRotation(_desiredForward, Vector3.up);
            //MotorSmoothRotation.TurnModel(modelTransform, _desiredForward);
            base.UpdateFromUpdatable();
        }

        public override void FixedUpdateFromUpdatable()
        {
            if (!Brain.IsEnabled) return;
            
            base.FixedUpdateFromUpdatable();
            _intendedDesiredVelocity = new Vector3(DesiredVelocity.x, 0, DesiredVelocity.y);
            LinearVelocity = MotorPhysicsContact.AdjustVelocityByContacts(DesiredVelocity);
            var moveOptions = Brain.Controls.IsDashing
                ? EntityMotorMoveOptions.GapCrossing
                : EntityMotorMoveOptions.Default;
            MotorTopDown.Move(UnityRigidbody, LinearVelocity, Time.fixedDeltaTime, moveOptions);
            MotorPhysicsContact.ResetContactCounter();
        }
        
        private void OnCollisionEnter(Collision collision)
        {
            if (!Brain.IsEnabled) return;
            
            MotorPhysicsContact.RegisterCollisionContacts(collision, MotorTopDown.MaxSlopeAngle);
            TryRaiseImpact(LinearVelocity);
        }
        
        private void OnCollisionStay(Collision collision)
        {
            if (!Brain.IsEnabled) return;
            
            MotorPhysicsContact.RegisterCollisionContacts(collision, MotorTopDown.MaxSlopeAngle);
            TryRaiseImpact(_intendedDesiredVelocity);
        }
        
        private void TryRaiseImpact(Vector3 intendedVelocity)
        {
            if (MotorPhysicsContact.HasImpactAgainstRegisteredContacts(intendedVelocity, 25f, out var bounceDirection))
            {
                var force = new Vector2(bounceDirection.x, bounceDirection.z) * intendedVelocity.magnitude;
                Proxy.Instance.EventBus.Raise(new ForceBackOnImpactEvent
                {
                    Force = force,
                });
            }
        }

        public void RefreshMovementNormal()
        {
            MotorTopDown.RefreshStableGroundNormalAt(UnityRigidbody.position);
        }

        public void ResetLastSafeGroundPosition()
        {
            UnityRigidbody.position = MotorTopDown.LastSafeGroundPosition;
            MotorTopDown.ResetFallingToAbyss();
        }
    }
}