using System.Collections.Generic;
using UnityEngine;
using EventsAppQuest.Core;

namespace EventsAppQuest.Presentation
{
    /// <summary>
    /// Prepara a camada de apontamento para futura integração com raycast/gaze.
    /// Mantém lista de alvos apontáveis e o "alvo apontado atual" (por agora derivado da seleção).
    /// Sem raycast real ainda: estrutura e fluxo prontos para substituição futura.
    /// </summary>
    public class QuestPointerPreparationController : MonoBehaviour
    {
        private readonly List<QuestPointableTarget> _pointableTargets = new List<QuestPointableTarget>();
        private string _pointedTargetId;
        private QuestPointerSourceMode _lastSourceMode = QuestPointerSourceMode.CenterScreenSimulated;
        private bool _pointedFromXRRaycast;
        private QuestXRRaycastHitResult _lastXRRaycastHit;

        /// <summary>Invocado quando o alvo apontado muda (ex.: após hit simulado ou seleção).</summary>
        public System.Action OnPointedTargetChanged;

        /// <summary>Lista de alvos apontáveis (painéis, hotspots, ações, navegação).</summary>
        public IReadOnlyList<QuestPointableTarget> PointableTargets => _pointableTargets;

        /// <summary>Modo de apontamento do último hit (para HUD).</summary>
        public QuestPointerSourceMode LastSourceMode => _lastSourceMode;

        /// <summary>Se true, o alvo apontado actual veio de raycast XR real (não simulado).</summary>
        public bool IsPointedFromXRRaycast => _pointedFromXRRaycast;

        /// <summary>Último resultado de raycast XR (para HUD/debug).</summary>
        public QuestXRRaycastHitResult LastXRRaycastHit => _lastXRRaycastHit;

        /// <summary>Atualiza a lista de alvos apontáveis a partir da sessão (espelha os alvos selecionáveis).</summary>
        public void RefreshPointableTargets(QuestPresentationSession session)
        {
            _pointableTargets.Clear();
            if (session == null) return;

            var hasSteps = session.GuidedSteps != null && session.GuidedSteps.Count > 0;
            var stepName = session.CurrentStep != null
                ? (session.CurrentStep.Title ?? session.CurrentStep.Description ?? "Passo")
                : "Passo atual";
            _pointableTargets.Add(new QuestPointableTarget
            {
                TargetId = "guided_step",
                TargetType = QuestPointableTargetType.Panel,
                WorldAnchorHint = "main_panel",
                HoverHint = stepName,
                SelectionHint = "Próx. passo",
                IsInteractable = hasSteps,
                RelatedSelectableTargetId = "guided_step"
            });

            var hasHotspots = session.Hotspots != null && session.Hotspots.Count > 0;
            var hotspotName = session.CurrentHotspot != null
                ? (session.CurrentHotspot.Title ?? session.CurrentHotspot.Description ?? "Hotspot")
                : "Hotspot atual";
            _pointableTargets.Add(new QuestPointableTarget
            {
                TargetId = "hotspot",
                TargetType = QuestPointableTargetType.HotspotMarker,
                WorldAnchorHint = "lateral_panel",
                HoverHint = hotspotName,
                SelectionHint = "Próx. hotspot",
                IsInteractable = hasHotspots,
                RelatedSelectableTargetId = "hotspot"
            });

            var hasStates = session.SceneStates != null && session.SceneStates.Count > 0;
            var stateName = session.CurrentSceneState != null
                ? (session.CurrentSceneState.Name ?? session.CurrentSceneState.Description ?? "Estado")
                : "Estado da cena";
            _pointableTargets.Add(new QuestPointableTarget
            {
                TargetId = "scene_state",
                TargetType = QuestPointableTargetType.Panel,
                WorldAnchorHint = "main_panel",
                HoverHint = stateName,
                SelectionHint = "Próx. estado",
                IsInteractable = hasStates,
                RelatedSelectableTargetId = "scene_state"
            });

            _pointableTargets.Add(new QuestPointableTarget
            {
                TargetId = "action_next",
                TargetType = QuestPointableTargetType.ActionTarget,
                WorldAnchorHint = "progress_panel",
                HoverHint = "Próx. passo",
                SelectionHint = "Avançar passo",
                IsInteractable = hasSteps,
                RelatedSelectableTargetId = "action_next"
            });

            _pointableTargets.Add(new QuestPointableTarget
            {
                TargetId = "action_restart",
                TargetType = QuestPointableTargetType.ActionTarget,
                WorldAnchorHint = "progress_panel",
                HoverHint = "Reiniciar",
                SelectionHint = "Reiniciar apresentação",
                IsInteractable = true,
                RelatedSelectableTargetId = "action_restart"
            });

            _pointableTargets.Add(new QuestPointableTarget
            {
                TargetId = "mode_toggle",
                TargetType = QuestPointableTargetType.NavigationTarget,
                WorldAnchorHint = "progress_panel",
                HoverHint = "Alternar modo",
                SelectionHint = "Guiado/Manual/Hotspot",
                IsInteractable = true,
                RelatedSelectableTargetId = "mode_toggle"
            });
        }

        /// <summary>Actualiza o alvo apontado a partir do resultado do raycast/gaze simulado.</summary>
        public void SetPointedFromSimulatedHit(QuestSimulatedPointerHit hit)
        {
            _pointedFromXRRaycast = false;
            if (hit != null)
            {
                _lastSourceMode = hit.SourceMode;
                var newId = hit.TargetId;
                if (newId != _pointedTargetId)
                {
                    _pointedTargetId = newId;
                    OnPointedTargetChanged?.Invoke();
                }
            }
            else
            {
                _pointedTargetId = null;
                OnPointedTargetChanged?.Invoke();
            }
        }

        /// <summary>Sincroniza o alvo apontado com o alvo selecionado (fallback / modo ManualCycleAssisted).</summary>
        public void SetPointedFromSelection(QuestSelectionController selectionController)
        {
            _pointedFromXRRaycast = false;
            var selected = selectionController?.GetSelectedTarget();
            var newId = selected?.TargetId ?? null;
            if (newId == _pointedTargetId) return;
            _pointedTargetId = newId;
            _lastSourceMode = QuestPointerSourceMode.ManualCycleAssisted;
            OnPointedTargetChanged?.Invoke();
        }

        /// <summary>Actualiza o alvo apontado a partir do resultado do raycast XR real.</summary>
        public void SetPointedFromXRRaycast(QuestXRRaycastHitResult hit)
        {
            _lastXRRaycastHit = hit;
            if (hit != null && hit.IsValidTarget && !string.IsNullOrEmpty(hit.HitTargetId))
            {
                _pointedFromXRRaycast = true;
                if (hit.HitTargetId != _pointedTargetId)
                {
                    _pointedTargetId = hit.HitTargetId;
                    OnPointedTargetChanged?.Invoke();
                }
            }
            else
            {
                _pointedFromXRRaycast = false;
            }
        }

        /// <summary>Define o alvo apontado por id (para uso externo ou raycast real).</summary>
        public void SetPointedTargetId(string targetId)
        {
            _pointedFromXRRaycast = false;
            if (targetId == _pointedTargetId) return;
            _pointedTargetId = targetId;
            OnPointedTargetChanged?.Invoke();
        }

        /// <summary>Id do alvo atualmente apontado (null se nenhum).</summary>
        public string GetPointedTargetId() => _pointedTargetId;

        /// <summary>Retorna o alvo apontado atual ou null.</summary>
        public QuestPointableTarget GetPointedTarget()
        {
            if (string.IsNullOrEmpty(_pointedTargetId)) return null;
            return GetPointableTargetById(_pointedTargetId);
        }

        /// <summary>Retorna o alvo apontável por id (para uso com alvo resolvido).</summary>
        public QuestPointableTarget GetPointableTargetById(string targetId)
        {
            if (string.IsNullOrEmpty(targetId)) return null;
            foreach (var t in _pointableTargets)
                if (t.TargetId == targetId) return t;
            return null;
        }
    }
}
