using UnityEngine;
using EventsAppQuest.Core;

namespace EventsAppQuest.Presentation
{
    /// <summary>
    /// Camada de input para a apresentação Quest: traduz teclado/gamepad (e futuramente input do headset) em
    /// comandos abstratos e envia ao dispatcher. Se o dispatcher não estiver ligado, usa fallback directo aos controladores.
    /// </summary>
    public class QuestPresentationInputAdapter : MonoBehaviour
    {
        public KeyCode NextStepKey = KeyCode.RightArrow;
        public KeyCode PreviousStepKey = KeyCode.LeftArrow;
        public KeyCode NextHotspotKey = KeyCode.H;
        public KeyCode PreviousHotspotKey = KeyCode.J;
        public KeyCode NextSceneStateKey = KeyCode.E;
        public KeyCode PreviousSceneStateKey = KeyCode.Q;
        public KeyCode ToggleNavigationModeKey = KeyCode.M;
        public KeyCode RestartPresentationKey = KeyCode.R;

        public KeyCode NextFocusKey = KeyCode.Tab;
        public KeyCode PreviousFocusKey = KeyCode.BackQuote;
        public KeyCode ActivateFocusKey = KeyCode.Space;
        public KeyCode ExitFocusModeKey = KeyCode.Escape;

        public KeyCode NextSelectableKey = KeyCode.F;
        public KeyCode PreviousSelectableKey = KeyCode.G;
        public KeyCode ConfirmSelectionKey = KeyCode.Return;
        public KeyCode CancelSelectionKey = KeyCode.Backspace;

        public KeyCode TogglePointerModeKey = KeyCode.P;
        public KeyCode ConfirmPointedTargetKey = KeyCode.Return;

        /// <summary>Origem usada ao emitir comandos (editor = KeyboardFallback ou EditorTest).</summary>
        public QuestPresentationInputSourceType InputSource = QuestPresentationInputSourceType.KeyboardFallback;

        private IQuestPresentationInputDispatcher _dispatcher;
        private QuestPresentationNavigationController _navController;
        private QuestPresentationFocusController _focusController;
        private QuestSelectionController _selectionController;
        private QuestPointerPreparationController _pointerPrepController;
        private QuestSimulatedPointerController _simulatedPointerController;

        /// <summary>Liga ao dispatcher central; quando definido, o adapter emite comandos em vez de chamar controladores directamente.</summary>
        public void BindDispatcher(IQuestPresentationInputDispatcher dispatcher)
        {
            _dispatcher = dispatcher;
        }

        public void Bind(QuestPresentationNavigationController navController)
        {
            _navController = navController;
        }

        public void BindFocus(QuestPresentationFocusController focusController)
        {
            _focusController = focusController;
        }

        public void BindSelection(QuestSelectionController selectionController)
        {
            _selectionController = selectionController;
        }

        public void BindPointer(QuestPointerPreparationController pointerPrepController, QuestSimulatedPointerController simulatedPointerController)
        {
            _pointerPrepController = pointerPrepController;
            _simulatedPointerController = simulatedPointerController;
        }

        private void Update()
        {
            if (_dispatcher != null)
            {
                TryEmit(TogglePointerModeKey, QuestPresentationInputCommandType.TogglePointerMode);
                if (TryEmit(ConfirmPointedTargetKey, QuestPresentationInputCommandType.ConfirmPointedTarget)) return;

                TryEmit(NextSelectableKey, QuestPresentationInputCommandType.NextSelectable);
                TryEmit(PreviousSelectableKey, QuestPresentationInputCommandType.PreviousSelectable);
                TryEmit(ConfirmSelectionKey, QuestPresentationInputCommandType.ConfirmSelection);
                TryEmit(CancelSelectionKey, QuestPresentationInputCommandType.CancelSelection);

                TryEmit(NextFocusKey, QuestPresentationInputCommandType.NextFocus);
                TryEmit(PreviousFocusKey, QuestPresentationInputCommandType.PreviousFocus);
                TryEmit(ActivateFocusKey, QuestPresentationInputCommandType.ActivateFocus);
                TryEmit(ExitFocusModeKey, QuestPresentationInputCommandType.ExitFocusMode);

                TryEmit(NextStepKey, QuestPresentationInputCommandType.NextStep);
                TryEmit(PreviousStepKey, QuestPresentationInputCommandType.PreviousStep);
                TryEmit(NextHotspotKey, QuestPresentationInputCommandType.NextHotspot);
                TryEmit(PreviousHotspotKey, QuestPresentationInputCommandType.PreviousHotspot);
                TryEmit(NextSceneStateKey, QuestPresentationInputCommandType.NextSceneState);
                TryEmit(PreviousSceneStateKey, QuestPresentationInputCommandType.PreviousSceneState);
                TryEmit(ToggleNavigationModeKey, QuestPresentationInputCommandType.ToggleNavigationMode);
                TryEmit(RestartPresentationKey, QuestPresentationInputCommandType.RestartPresentation);
                return;
            }

            FallbackUpdate();
        }

        private bool TryEmit(KeyCode key, QuestPresentationInputCommandType type)
        {
            if (!Input.GetKeyDown(key) || _dispatcher == null) return false;
            var cmd = QuestPresentationInputCommand.Create(type, InputSource, null);
            _dispatcher.SetCurrentSource(InputSource);
            return _dispatcher.Dispatch(cmd);
        }

        private void FallbackUpdate()
        {
            if (_simulatedPointerController != null && Input.GetKeyDown(TogglePointerModeKey))
                _simulatedPointerController.CyclePointerMode();

            if (_pointerPrepController != null && _selectionController != null && Input.GetKeyDown(ConfirmPointedTargetKey))
            {
                var pointed = _pointerPrepController.GetPointedTarget();
                if (pointed != null)
                {
                    _selectionController.ConfirmPointedTarget(pointed);
                    return;
                }
            }

            if (_selectionController != null)
            {
                if (Input.GetKeyDown(NextSelectableKey)) _selectionController.ProcessCommand(QuestInteractionCommand.FromType(QuestInteractionCommandType.NextSelectable));
                else if (Input.GetKeyDown(PreviousSelectableKey)) _selectionController.ProcessCommand(QuestInteractionCommand.FromType(QuestInteractionCommandType.PreviousSelectable));
                else if (Input.GetKeyDown(ConfirmSelectionKey)) _selectionController.ProcessCommand(QuestInteractionCommand.FromType(QuestInteractionCommandType.ConfirmSelection));
                else if (Input.GetKeyDown(CancelSelectionKey)) _selectionController.ProcessCommand(QuestInteractionCommand.FromType(QuestInteractionCommandType.CancelSelection));
            }

            if (_focusController != null)
            {
                if (Input.GetKeyDown(NextFocusKey)) _focusController.NextFocus();
                else if (Input.GetKeyDown(PreviousFocusKey)) _focusController.PreviousFocus();
                else if (Input.GetKeyDown(ActivateFocusKey)) _focusController.ActivateFocus();
                else if (Input.GetKeyDown(ExitFocusModeKey)) _focusController.ExitFocusMode();
            }

            if (_navController == null) return;

            if (Input.GetKeyDown(NextStepKey)) _navController.NextStep();
            else if (Input.GetKeyDown(PreviousStepKey)) _navController.PreviousStep();
            else if (Input.GetKeyDown(NextHotspotKey)) _navController.NextHotspot();
            else if (Input.GetKeyDown(PreviousHotspotKey)) _navController.PreviousHotspot();
            else if (Input.GetKeyDown(NextSceneStateKey)) _navController.NextSceneState();
            else if (Input.GetKeyDown(PreviousSceneStateKey)) _navController.PreviousSceneState();
            else if (Input.GetKeyDown(ToggleNavigationModeKey)) _navController.ToggleNavigationMode();
            else if (Input.GetKeyDown(RestartPresentationKey)) _navController.RestartPresentation();
        }
    }
}
