using UnityEngine;
using UnityEngine.Events;

public class SlidingDoor : MonoBehaviour
{
    public enum SlideAxis { X, Y, Z }
    public enum SlideDirection { Positive = 1, Negative = -1 }

    [Header("Slide Settings")]
    [Tooltip("Axis in parent space (or world space if no parent) the door slides along.")]
    [SerializeField] private SlideAxis axis = SlideAxis.X;

    [Tooltip("Which way along the axis the door opens.")]
    [SerializeField] private SlideDirection direction = SlideDirection.Positive;

    [Tooltip("How far the door travels when fully open.")]
    [SerializeField] private float slideDistance = 2f;

    [Tooltip("Movement speed (units per second).")]
    [SerializeField] private float speed = 3f;

    [Header("Start State")]
    [SerializeField] private bool startOpen = false;

    [Header("Events")]
    public UnityEvent OnOpened;
    public UnityEvent OnClosed;

    private Vector3 m_closedPos;
    private Vector3 m_openPos;
    private Vector3 m_targetPos;
    private bool m_isOpen;
    private bool m_eventFiredOpen;
    private bool m_eventFiredClosed;

    private void Awake()
    {
        m_closedPos = transform.localPosition;
        m_openPos = m_closedPos + GetParentSpaceSlideVector() * slideDistance;

        if (startOpen)
        {
            transform.localPosition = m_openPos;
            m_isOpen = true;
        }

        m_targetPos = m_isOpen ? m_openPos : m_closedPos;
    }

    private void Update()
    {
        transform.localPosition = Vector3.MoveTowards(
            transform.localPosition, m_targetPos, speed * Time.deltaTime);

        if (Vector3.Distance(transform.localPosition, m_openPos) < 0.01f && !m_eventFiredOpen)
        {
            m_eventFiredOpen = true;
            m_eventFiredClosed = false;
            OnOpened?.Invoke();
        }
        else if (Vector3.Distance(transform.localPosition, m_closedPos) < 0.01f && !m_eventFiredClosed)
        {
            m_eventFiredClosed = true;
            m_eventFiredOpen = false;
            OnClosed?.Invoke();
        }
    }

    public void Open()
    {
        m_isOpen = true;
        m_targetPos = m_openPos;
    }

    public void Close()
    {
        m_isOpen = false;
        m_targetPos = m_closedPos;
    }

    public void Toggle()
    {
        if (m_isOpen)
            Close();
        else
            Open();
    }

    private Vector3 GetParentSpaceSlideVector()
    {
        float sign = (float)direction;
        return axis switch
        {
            SlideAxis.X => new Vector3(sign, 0f, 0f),
            SlideAxis.Y => new Vector3(0f, sign, 0f),
            SlideAxis.Z => new Vector3(0f, 0f, sign),
            _           => Vector3.right,
        };
    }

    private Vector3 GetWorldSpaceSlideVector()
    {
        return transform.parent != null
            ? transform.parent.TransformDirection(GetParentSpaceSlideVector()).normalized
            : GetParentSpaceSlideVector().normalized;
    }

#if UNITY_EDITOR
    private void OnDrawGizmos()
    {
        Vector3 worldClosed = transform.position;

        Vector3 slideVec = GetWorldSpaceSlideVector() * slideDistance;
        Gizmos.color = Color.cyan;
        Gizmos.DrawLine(worldClosed, worldClosed + slideVec);
        Gizmos.DrawWireSphere(worldClosed + slideVec, 0.08f);
    }
#endif
}
