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

namespace EventsAppQuest.Presentation
{
    /// <summary>
    /// Controlador de raycast/gaze simulado: determina o alvo apontado actual com critério espacial/situacional
    /// (prioridade por painel, foco, disponibilidade), sem raycast físico. Prepara troca futura por raycast/gaze real.
    /// </summary>
    public class QuestSimulatedPointerController : MonoBehaviour
    {
        private QuestPointerSourceMode _currentSourceMode = QuestPointerSourceMode.CenterScreenSimulated;

        /// <summary>Invocado quando o modo de apontamento muda.</summary>
        public System.Action OnPointerModeChanged;

        /// <summary>Modo de apontamento actual.</summary>
        public QuestPointerSourceMode CurrentSourceMode => _currentSourceMode;

        /// <summary>Cicla o modo: FocusDriven → CenterScreenSimulated → ManualCycleAssisted → FocusDriven.</summary>
        public QuestPointerSourceMode CyclePointerMode()
        {
            var next = (int)_currentSourceMode + 1;
            if (next > 2) next = 0;
            _currentSourceMode = (QuestPointerSourceMode)next;
            OnPointerModeChanged?.Invoke();
            return _currentSourceMode;
        }

        /// <summary>Define o modo de apontamento (para restauro ou testes).</summary>
        public void SetPointerSourceMode(QuestPointerSourceMode mode)
        {
            if (_currentSourceMode == mode) return;
            _currentSourceMode = mode;
            OnPointerModeChanged?.Invoke();
        }

        /// <summary>Executa o apontamento simulado e devolve o hit actual (ou null se nenhum alvo válido).</summary>
        public QuestSimulatedPointerHit PerformSimulatedHit(
            QuestPresentationSession session,
            QuestPresentationFocusController focusController,
            QuestSelectionController selectionController,
            IReadOnlyList<QuestPointableTarget> pointableTargets)
        {
            if (pointableTargets == null || pointableTargets.Count == 0) return null;

            switch (_currentSourceMode)
            {
                case QuestPointerSourceMode.FocusDriven:
                    return ComputeFocusDrivenHit(session, focusController, pointableTargets);
                case QuestPointerSourceMode.CenterScreenSimulated:
                    return ComputeCenterScreenSimulatedHit(session, focusController, pointableTargets);
                case QuestPointerSourceMode.ManualCycleAssisted:
                    return ComputeManualCycleHit(selectionController, pointableTargets);
                default:
                    return ComputeCenterScreenSimulatedHit(session, focusController, pointableTargets);
            }
        }

        private static QuestSimulatedPointerHit ComputeFocusDrivenHit(
            QuestPresentationSession session,
            QuestPresentationFocusController focusController,
            IReadOnlyList<QuestPointableTarget> pointableTargets)
        {
            if (session == null || !session.IsInteractionModeActive)
                return BestAvailableFromList(pointableTargets, QuestPointerSourceMode.FocusDriven);

            var focus = session.FocusedTargetType;
            string primaryTargetId = null;
            switch (focus)
            {
                case QuestPresentationFocusTargetType.GuidedStepPanel: primaryTargetId = "guided_step"; break;
                case QuestPresentationFocusTargetType.HotspotPanel: primaryTargetId = "hotspot"; break;
                case QuestPresentationFocusTargetType.SceneStatePanel: primaryTargetId = "scene_state"; break;
                case QuestPresentationFocusTargetType.ProgressPanel: primaryTargetId = "action_restart"; break;
                case QuestPresentationFocusTargetType.ActionPanel: primaryTargetId = "mode_toggle"; break;
            }

            foreach (var t in pointableTargets)
                if (t.TargetId == primaryTargetId)
                    return new QuestSimulatedPointerHit
                    {
                        TargetId = t.TargetId,
                        TargetType = t.TargetType,
                        HitScore = 1f,
                        IsInteractable = t.IsInteractable,
                        HitHint = t.HoverHint,
                        SourceMode = QuestPointerSourceMode.FocusDriven
                    };

            return BestAvailableFromList(pointableTargets, QuestPointerSourceMode.FocusDriven);
        }

        private static QuestSimulatedPointerHit ComputeCenterScreenSimulatedHit(
            QuestPresentationSession session,
            QuestPresentationFocusController focusController,
            IReadOnlyList<QuestPointableTarget> pointableTargets)
        {
            QuestPointableTarget best = null;
            float bestScore = -1f;

            foreach (var t in pointableTargets)
            {
                var centrality = GetCentralityScore(t.WorldAnchorHint);
                var focusBoost = session != null && session.IsInteractionModeActive && IsFocusedPanelTarget(session.FocusedTargetType, t.TargetId) ? 0.25f : 0f;
                var availability = t.IsInteractable ? 0.1f : 0f;
                var score = centrality + focusBoost + availability;
                if (score > bestScore)
                {
                    bestScore = score;
                    best = t;
                }
            }

            if (best == null) return null;
            return new QuestSimulatedPointerHit
            {
                TargetId = best.TargetId,
                TargetType = best.TargetType,
                HitScore = Mathf.Clamp01(bestScore),
                IsInteractable = best.IsInteractable,
                HitHint = best.HoverHint,
                SourceMode = QuestPointerSourceMode.CenterScreenSimulated
            };
        }

        private static bool IsFocusedPanelTarget(QuestPresentationFocusTargetType focus, string targetId)
        {
            switch (focus)
            {
                case QuestPresentationFocusTargetType.GuidedStepPanel: return targetId == "guided_step";
                case QuestPresentationFocusTargetType.HotspotPanel: return targetId == "hotspot";
                case QuestPresentationFocusTargetType.SceneStatePanel: return targetId == "scene_state";
                case QuestPresentationFocusTargetType.ProgressPanel: return targetId == "action_restart" || targetId == "action_next";
                case QuestPresentationFocusTargetType.ActionPanel: return targetId == "mode_toggle";
                default: return false;
            }
        }

        private static float GetCentralityScore(string worldAnchorHint)
        {
            if (string.IsNullOrEmpty(worldAnchorHint)) return 0.5f;
            switch (worldAnchorHint)
            {
                case "main_panel": return 1f;
                case "lateral_panel": return 0.75f;
                case "progress_panel": return 0.5f;
                default: return 0.5f;
            }
        }

        private static QuestSimulatedPointerHit ComputeManualCycleHit(
            QuestSelectionController selectionController,
            IReadOnlyList<QuestPointableTarget> pointableTargets)
        {
            var selected = selectionController?.GetSelectedTarget();
            if (selected == null)
                return BestAvailableFromList(pointableTargets, QuestPointerSourceMode.ManualCycleAssisted);

            foreach (var t in pointableTargets)
                if (t.TargetId == selected.TargetId)
                    return new QuestSimulatedPointerHit
                    {
                        TargetId = t.TargetId,
                        TargetType = t.TargetType,
                        HitScore = 1f,
                        IsInteractable = t.IsInteractable,
                        HitHint = t.HoverHint,
                        SourceMode = QuestPointerSourceMode.ManualCycleAssisted
                    };

            return BestAvailableFromList(pointableTargets, QuestPointerSourceMode.ManualCycleAssisted);
        }

        private static QuestSimulatedPointerHit BestAvailableFromList(IReadOnlyList<QuestPointableTarget> list, QuestPointerSourceMode sourceMode)
        {
            if (list == null || list.Count == 0) return null;
            var first = list[0];
            return new QuestSimulatedPointerHit
            {
                TargetId = first.TargetId,
                TargetType = first.TargetType,
                HitScore = 0.5f,
                IsInteractable = first.IsInteractable,
                HitHint = first.HoverHint,
                SourceMode = sourceMode
            };
        }
    }
}
