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

namespace EventsAppQuest.Presentation
{
    /// <summary>
    /// Controlador de seleção de alvos na apresentação Quest: regista alvos selecionáveis (passo, hotspot, estado, ações),
    /// alterna seleção, confirma/cancela e executa a ação do alvo selecionado. Compatível com o foco existente.
    /// Preparado para futura substituição por input real (raycast/apontamento).
    /// </summary>
    public class QuestSelectionController : MonoBehaviour
    {
        private QuestPresentationSession _session;
        private QuestPresentationNavigationController _navController;
        private readonly List<QuestSelectableTarget> _targets = new List<QuestSelectableTarget>();
        private int _selectedIndex = -1;

        /// <summary>Invocado quando a seleção ou a lista de alvos mudam.</summary>
        public System.Action OnSelectionChanged;

        /// <summary>Invocado quando uma confirmação é executada (dwell ou explícita), com o TargetId confirmado.</summary>
        public System.Action<string> OnConfirmed;

        public void Bind(QuestPresentationSession session, QuestPresentationNavigationController navController)
        {
            _session = session;
            _navController = navController;
        }

        /// <summary>Atualiza a lista de alvos a partir da sessão (passo atual, hotspot, estado, botões, modo).</summary>
        public void RefreshTargets()
        {
            _targets.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";
            _targets.Add(new QuestSelectableTarget
            {
                TargetId = "guided_step",
                TargetType = QuestSelectableTargetType.GuidedStep,
                DisplayName = stepName,
                IsCurrentlyAvailable = hasSteps,
                SelectionHint = "Próx. passo",
                RelatedDataKey = _session.CurrentGuidedStepIndex.ToString()
            });

            var hasHotspots = _session.Hotspots != null && _session.Hotspots.Count > 0;
            var hotspotName = _session.CurrentHotspot != null
                ? (_session.CurrentHotspot.Title ?? _session.CurrentHotspot.Description ?? "Hotspot")
                : "Hotspot atual";
            _targets.Add(new QuestSelectableTarget
            {
                TargetId = "hotspot",
                TargetType = QuestSelectableTargetType.Hotspot,
                DisplayName = hotspotName,
                IsCurrentlyAvailable = hasHotspots,
                SelectionHint = "Próx. hotspot",
                RelatedDataKey = _session.CurrentHotspotIndex.ToString()
            });

            var hasStates = _session.SceneStates != null && _session.SceneStates.Count > 0;
            var stateName = _session.CurrentSceneState != null
                ? (_session.CurrentSceneState.Name ?? _session.CurrentSceneState.Description ?? "Estado")
                : "Estado da cena";
            _targets.Add(new QuestSelectableTarget
            {
                TargetId = "scene_state",
                TargetType = QuestSelectableTargetType.SceneState,
                DisplayName = stateName,
                IsCurrentlyAvailable = hasStates,
                SelectionHint = "Próx. estado",
                RelatedDataKey = _session.CurrentSceneStateIndex.ToString()
            });

            _targets.Add(new QuestSelectableTarget
            {
                TargetId = "action_next",
                TargetType = QuestSelectableTargetType.ActionButton,
                DisplayName = "Próx. passo",
                IsCurrentlyAvailable = hasSteps,
                SelectionHint = "Avançar passo",
                RelatedDataKey = "next_step"
            });

            _targets.Add(new QuestSelectableTarget
            {
                TargetId = "action_restart",
                TargetType = QuestSelectableTargetType.ActionButton,
                DisplayName = "Reiniciar",
                IsCurrentlyAvailable = true,
                SelectionHint = "Reiniciar apresentação",
                RelatedDataKey = "restart"
            });

            _targets.Add(new QuestSelectableTarget
            {
                TargetId = "mode_toggle",
                TargetType = QuestSelectableTargetType.ModeToggle,
                DisplayName = "Alternar modo",
                IsCurrentlyAvailable = true,
                SelectionHint = "Guiado/Manual/Hotspot",
                RelatedDataKey = "mode"
            });

            if (_selectedIndex >= _targets.Count)
                _selectedIndex = _targets.Count > 0 ? _targets.Count - 1 : -1;
            if (_selectedIndex < 0 && _targets.Count > 0)
                _selectedIndex = 0;
        }

        /// <summary>Seleciona o próximo alvo (cíclico).</summary>
        public void NextSelectable()
        {
            if (_targets.Count == 0) return;
            _selectedIndex = (_selectedIndex + 1) % _targets.Count;
            OnSelectionChanged?.Invoke();
        }

        /// <summary>Seleciona o alvo anterior (cíclico).</summary>
        public void PreviousSelectable()
        {
            if (_targets.Count == 0) return;
            _selectedIndex = _selectedIndex <= 0 ? _targets.Count - 1 : _selectedIndex - 1;
            OnSelectionChanged?.Invoke();
        }

        /// <summary>Confirma a seleção e executa a ação do alvo selecionado.</summary>
        public void ConfirmSelection()
        {
            var target = GetSelectedTarget();
            if (target == null || _navController == null) return;
            if (!target.IsCurrentlyAvailable && (target.TargetType == QuestSelectableTargetType.GuidedStep || target.TargetType == QuestSelectableTargetType.Hotspot || target.TargetType == QuestSelectableTargetType.SceneState))
                return;

            switch (target.TargetType)
            {
                case QuestSelectableTargetType.GuidedStep:
                    _navController.NextStep();
                    break;
                case QuestSelectableTargetType.Hotspot:
                    break;
                case QuestSelectableTargetType.SceneState:
                    _navController.NextSceneState();
                    break;
                case QuestSelectableTargetType.ActionButton:
                    if (target.RelatedDataKey == "next_step") _navController.NextStep();
                    else if (target.RelatedDataKey == "restart") _navController.RestartPresentation();
                    break;
                case QuestSelectableTargetType.ModeToggle:
                    _navController.ToggleNavigationMode();
                    break;
            }
            RefreshTargets();
            OnSelectionChanged?.Invoke();
            OnConfirmed?.Invoke(target.TargetId);
        }

        /// <summary>Cancela a seleção (limpa o alvo selecionado; navegação/foco continuam disponíveis).</summary>
        public void CancelSelection()
        {
            _selectedIndex = -1;
            OnSelectionChanged?.Invoke();
        }

        /// <summary>Processa um comando de interação (preparado para input real).</summary>
        public void ProcessCommand(QuestInteractionCommand command)
        {
            switch (command.Type)
            {
                case QuestInteractionCommandType.NextSelectable: NextSelectable(); break;
                case QuestInteractionCommandType.PreviousSelectable: PreviousSelectable(); break;
                case QuestInteractionCommandType.ConfirmSelection: ConfirmSelection(); break;
                case QuestInteractionCommandType.CancelSelection: CancelSelection(); break;
            }
        }

        /// <summary>Define o alvo selecionado por id (para confirmar o alvo apontado sem ciclo).</summary>
        public bool SetSelectedTargetById(string targetId)
        {
            if (string.IsNullOrEmpty(targetId)) return false;
            for (int i = 0; i < _targets.Count; i++)
            {
                if (_targets[i].TargetId == targetId)
                {
                    _selectedIndex = i;
                    OnSelectionChanged?.Invoke();
                    return true;
                }
            }
            return false;
        }

        /// <summary>Confirma o alvo apontado: alinha seleção ao apontado e executa ConfirmSelection.</summary>
        public void ConfirmPointedTarget(QuestPointableTarget pointed)
        {
            if (pointed == null) return;
            var id = pointed.RelatedSelectableTargetId ?? pointed.TargetId;
            if (SetSelectedTargetById(id))
                ConfirmSelection();
        }

        /// <summary>Retorna o alvo atualmente selecionado ou null.</summary>
        public QuestSelectableTarget GetSelectedTarget()
        {
            if (_selectedIndex < 0 || _selectedIndex >= _targets.Count) return null;
            return _targets[_selectedIndex];
        }

        /// <summary>Índice do alvo selecionado (-1 se nenhum).</summary>
        public int SelectedIndex => _selectedIndex;

        /// <summary>Quantidade de alvos registados.</summary>
        public int TargetCount => _targets.Count;

        /// <summary>Tipo do alvo selecionado (para destaque visual por painel).</summary>
        public QuestSelectableTargetType? GetSelectedTargetType()
        {
            var t = GetSelectedTarget();
            return t?.TargetType;
        }
    }
}
