using UnityEngine;
using EventsAppQuest.Core;

namespace EventsAppQuest.Presentation
{
    /// <summary>
    /// Controlador de hover/dwell temporal: acompanha quanto tempo um alvo permanece apontado,
    /// reseta ao mudar de alvo, marca quando o dwell está pronto e permite confirmação por dwell ou explícita (configurável).
    /// Preparado para futura integração com gaze real.
    /// </summary>
    public class QuestHoverDwellController : MonoBehaviour
    {
        [Tooltip("Tempo em segundos para dwell completo (alvo pronto para confirmar).")]
        [SerializeField] private float _requiredDwellSeconds = 1.2f;

        [Tooltip("Número mínimo de frames no mesmo alvo para considerar hover estável.")]
        [SerializeField] private int _minStableFrames = 3;

        private QuestTargetHoverState _currentState;
        private string _lastPointedTargetId;
        private int _stableFrameCount;
        private bool _dwellReadyFired;

        /// <summary>Invocado uma vez quando o dwell atinge o tempo requerido (para auto-confirmar ou feedback).</summary>
        public System.Action<string, QuestHoverSourceMode> OnDwellReady;

        /// <summary>Estado actual de hover/dwell (pode ser null se nenhum alvo apontado).</summary>
        public QuestTargetHoverState CurrentState => _currentState;

        /// <summary>Tempo em segundos necessário para dwell completo.</summary>
        public float RequiredDwellSeconds => _requiredDwellSeconds;

        /// <summary>Define o tempo requerido de dwell em segundos.</summary>
        public void SetRequiredDwellSeconds(float seconds)
        {
            _requiredDwellSeconds = Mathf.Max(0.1f, seconds);
        }

        /// <summary>Actualiza o estado de hover/dwell com o alvo apontado actual. Chamar a cada frame após o pointer/raycast.</summary>
        /// <param name="deltaTime">Tempo desde o último frame.</param>
        /// <param name="pointedTargetId">Id do alvo apontado (null se nenhum).</param>
        /// <param name="sourceMode">Origem do apontamento (simulado, XR raycast, futuro gaze).</param>
        public void UpdateHover(float deltaTime, string pointedTargetId, QuestHoverSourceMode sourceMode)
        {
            if (string.IsNullOrEmpty(pointedTargetId))
            {
                _currentState = null;
                _lastPointedTargetId = null;
                _stableFrameCount = 0;
                _dwellReadyFired = false;
                return;
            }

            if (pointedTargetId != _lastPointedTargetId)
            {
                _lastPointedTargetId = pointedTargetId;
                _stableFrameCount = 0;
                _dwellReadyFired = false;
                _currentState = new QuestTargetHoverState
                {
                    TargetId = pointedTargetId,
                    HoverElapsedSeconds = 0f,
                    RequiredDwellSeconds = _requiredDwellSeconds,
                    IsDwellReady = false,
                    IsHoverStable = false,
                    HoverSourceMode = sourceMode,
                    Notes = "Novo alvo"
                };
            }

            if (_currentState == null) return;

            _stableFrameCount++;
            _currentState.HoverElapsedSeconds += deltaTime;
            _currentState.RequiredDwellSeconds = _requiredDwellSeconds;
            _currentState.IsHoverStable = _stableFrameCount >= _minStableFrames;
            _currentState.HoverSourceMode = sourceMode;

            if (_currentState.HoverElapsedSeconds >= _requiredDwellSeconds)
            {
                _currentState.IsDwellReady = true;
                if (!_dwellReadyFired)
                {
                    _dwellReadyFired = true;
                    OnDwellReady?.Invoke(_currentState.TargetId, _currentState.HoverSourceMode);
                }
            }
            else
                _currentState.IsDwellReady = false;
        }

        /// <summary>Consome o estado "dwell pronto" (após confirmação automática ou explícita) para evitar repetição. Reseta o tempo de dwell do alvo actual.</summary>
        public void ConsumeDwellConfirm()
        {
            _dwellReadyFired = true;
            if (_currentState != null)
            {
                _currentState.HoverElapsedSeconds = 0f;
                _currentState.IsDwellReady = false;
            }
        }

        /// <summary>Retorna true se o dwell está pronto e ainda não foi consumido nesta permanência no alvo. Após chamar ConsumeDwellConfirm, deixa de estar pronto até dwell de novo.</summary>
        public bool IsDwellReadyToConfirm()
        {
            return _currentState != null && _currentState.IsDwellReady && !_dwellReadyFired;
        }

        /// <summary>Progresso normalizado do dwell (0 a 1) para feedback visual.</summary>
        public float GetDwellProgressNormalized()
        {
            if (_currentState == null || _requiredDwellSeconds <= 0f) return 0f;
            return Mathf.Clamp01(_currentState.HoverElapsedSeconds / _requiredDwellSeconds);
        }
    }
}
