using System.Collections;
using System.Collections.Generic;
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;

namespace GGJ2021
{
    public class PlayerCamouflage : MonoBehaviour
    {
        [HideInInspector]
        public bool IsHidden;

        [SerializeField]
        private LayerMask camouflageWallLayerMask = default;

        [SerializeField]
        private CamouflageData[] camouflageItems = null;

        [SerializeField]
        private RawImage textureUI = null;

        // [SerializeField]
        // private TMPro.TMP_Text debugHiddenText;

        [SerializeField]
        private Material[] chameleonSkinMats = null;

        [Header("SFX")]
        [SerializeField]
        private FMODUnity.StudioEventEmitter robeSfx = null;

        [SerializeField]
        private FMODUnity.StudioEventEmitter camoSelect = null;

        private CapsuleCollider playerCollider;
        private int selectedCamouflageItemIndex = 0;
        private bool movingPlayerTowardsWall = false;

        private void Awake()
        {
            playerCollider = GetComponent<CapsuleCollider>();

            IsHidden = false;
            movingPlayerTowardsWall = false;
        }

        private void Start()
        {
            SetPlayerTexture();

            foreach (var mat in chameleonSkinMats)
                mat.SetFloat("_Blend", 0f);
        }

        public bool CheckIfNextToCamouflage()
        {
            var colliders = Physics.OverlapSphere(transform.position, 1f, camouflageWallLayerMask);
            var nearestCollider = GetNearestCollider(transform.position, colliders);

            if (nearestCollider)
                return MovePlayerToWall(nearestCollider);

            return nearestCollider;
        }

        public void ReleaseFromWall()
        {
            // Don't move player away from wall if they're still moving towards it, otherwise get some weird jumps.
            if (movingPlayerTowardsWall)
            {
                IsHidden = false;
            }
            else
            {
                transform.DOMove(transform.position + transform.forward * 0.01f, 0.2f).OnComplete(() => IsHidden = false);
            }

            robeSfx.Play();
            FadePlayerTexture(0f);
        }

        public void HandleChangeCamo(bool selectRight)
        {
            if (selectRight)
            {
                int nextIndex = (selectedCamouflageItemIndex + 1) % camouflageItems.Length;
                selectedCamouflageItemIndex = nextIndex;
            }
            else
            {
                int nextIndex = (selectedCamouflageItemIndex - 1 % camouflageItems.Length + camouflageItems.Length) % camouflageItems.Length;
                selectedCamouflageItemIndex = nextIndex;
            }

            camoSelect.Play();
            SetPlayerTexture();
        }

        private void FadePlayerTexture(float targetBlend)
        {
            foreach (var mat in chameleonSkinMats)
                mat.DOFloat(targetBlend, "_Blend", 0.45f);

        }

        private void SetPlayerTexture()
        {
            textureUI.texture = camouflageItems[selectedCamouflageItemIndex].texture;
            foreach (var mat in chameleonSkinMats)
                mat.SetTexture("_CamoTex", camouflageItems[selectedCamouflageItemIndex].texture);
        }

        private Collider GetNearestCollider(Vector3 pos, Collider[] colliders)
        {
            float bestDistance = 99999.0f;
            Collider bestCollider = null;

            foreach (Collider collider in colliders)
            {
                float distance = Vector3.Distance(pos, collider.transform.position);

                if (distance < bestDistance)
                {
                    bestDistance = distance;
                    bestCollider = collider;
                }
            }

            return bestCollider;
        }

        private bool MovePlayerToWall(Collider wallCollider)
        {
            Vector3 closestPoint = wallCollider.ClosestPoint(transform.position);
            Debug.DrawRay(transform.position, wallCollider.transform.position - transform.position);
            Ray ray = new Ray(transform.position, wallCollider.transform.position - transform.position);

            if (wallCollider.Raycast(ray, out RaycastHit hitInfo, 100f))
            {
                // Debug.Log(hitInfo.normal);
                // Debug.DrawRay(hitInfo.point, hitInfo.normal, Color.red, 3f);
                movingPlayerTowardsWall = true;

                // Rotate player towards wall
                var targetRot = Quaternion.LookRotation(hitInfo.normal, Vector3.up);
                transform.DORotateQuaternion(targetRot, 0.35f);

                // Move player to wall (with offset)
                var targetPosRaw = new Vector3(hitInfo.point.x, transform.position.y, hitInfo.point.z);
                var targetPos = targetPosRaw + hitInfo.normal * playerCollider.radius; // slightly off the wall
                transform.DOMove(targetPos, 0.35f).OnComplete(() =>
                {
                    movingPlayerTowardsWall = false;
                });

                FadePlayerTexture(1f);

                CheckIfHidden(hitInfo.transform.gameObject);

                robeSfx.Play();

                return true;
            }

            return false;
        }

        private void CheckIfHidden(GameObject wallGO)
        {
            if (wallGO.TryGetComponent<CamouflageSurface>(out CamouflageSurface component))
            {
                if (component.camouflageType == camouflageItems[selectedCamouflageItemIndex])
                {
                    IsHidden = true;
                }
            }
        }
    }

}
