using System;
using EscapeRoomEngine.VR.Runtime;
using NaughtyAttributes;
using Station46.Scripts;
using UnityEngine;
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;

namespace Station46.Modules.Elevated_Platform.Scripts
{
    [RequireComponent(typeof(Animator), typeof(Collider))]
    public class PlatformElevator : MonoBehaviour
    {
        public enum Status
        {
            Bottom, Top, Moving
        }
        
        private static readonly int
            AscendHash = Animator.StringToHash("Ascend"),
            DescendHash = Animator.StringToHash("Descend");
        
        [BoxGroup("Internal")] [SerializeField] private HoloButton button;

        [ShowNativeProperty]
        internal Status ElevatorStatus
        {
            get => _status;
            set
            {
                _status = value;
                switch (value)
                {
                    case Status.Bottom:
                    case Status.Top:
                        ReleasePlayer();
                        if (_leftElevatorWhileMoving)
                        {
                            button.hideWhenDisabled = true;
                            button.Enable();
                            button.Disable();
                        }
                        else
                        {
                            button.Enable();
                        }
                        _leftElevatorWhileMoving = false;
                        break;
                    case Status.Moving:
                        button.hideWhenDisabled = false;
                        button.Disable();
                        CapturePlayer();
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }

        private Status _status = Status.Bottom;
        private Animator _animator;
        private Transform _previousPlayerParent;
        private bool _leftElevatorWhileMoving;

        private void Awake()
        {
            _animator = GetComponent<Animator>();
        }

        private void Start()
        {
            button.ButtonEvent += (_, type) =>
            {
                if (type == ButtonEventType.Pressed)
                {
                    Activate();
                }
            };
        }

        private void CapturePlayer()
        {
            Logger.Log($"{this} captured player.", LogType.PuzzleDetail);
            
            _previousPlayerParent = Player.Instance.transform.parent;
            Player.Instance.transform.SetParent(transform);
        }

        private void ReleasePlayer()
        {
            Logger.Log($"{this} released player.", LogType.PuzzleDetail);

            Player.Instance.transform.SetParent(_previousPlayerParent);
        }

        public void Activate()
        {
            switch (ElevatorStatus)
            {
                case Status.Bottom:
                    Logger.Log($"{this} ascending.", LogType.PuzzleDetail);
                
                    ElevatorStatus = Status.Moving;
                    _animator.SetTrigger(AscendHash);
                    break;
                case Status.Top:
                    Logger.Log($"{this} descending.", LogType.PuzzleDetail);
                
                    ElevatorStatus = Status.Moving;
                    _animator.SetTrigger(DescendHash);
                    break;
                case Status.Moving:
                    Logger.Log($"{this} is already moving.", LogType.PuzzleDetail);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        private void OnTriggerEnter(Collider other)
        {
            if (other.CompareTag("MainCamera"))
            {
                if (_status == Status.Moving)
                {
                    _leftElevatorWhileMoving = false;
                }
                else
                {
                    button.Enable();
                }
            }
        }

        private void OnTriggerExit(Collider other)
        {
            if (other.CompareTag("MainCamera"))
            {
                if (_status == Status.Moving)
                {
                    _leftElevatorWhileMoving = true;
                }
                else
                {
                    button.hideWhenDisabled = true;
                    button.Disable();
                }
            }
        }
    }
}