using System;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Windows;

public enum InputState { Started, Performing, Canceled }

public class InputManager : MonoBehaviour
{
    public static InputManager Instance;

    private PlayerInput _playerInput;
    private InputActionMap _globalInputActionMap;
    private InputActionMap _uiInputActionMap;
    private InputActionMap _characterInputActionMap;

    //콜백 이벤트들
    //캐릭터 조작관련은 따로 분류
    public event Action<float> OnMouseScrollEvent;
    public event Action<Vector2> OnMoveEvent;
    public event Action<InputState> OnSprintEvent;
    public event Action<InputState> OnJumpEvent;
    public event Action<InputState> OnAimToggleEvent;
    public event Action<Vector2> OnLookEvent;
    public event Action<InputState> OnDodgeEvent;
    public event Action OnNormalAttackEvent;
    public event Action OnHeavyAttackEvent;
    public event Action OnInteractionEvent;


    //키조작
    public event Action OnKeyDown_UpArrowEvent;
    public event Action OnKeyDown_DownArrowEvent;
    public event Action OnKeyDown_EnterEvent;
    public event Action OnKeyDown_IKeyEvent;



    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this; //만들어진 자신을 인스턴스로 설정
        }
        else
        {
            Destroy(gameObject); //이미 인스턴스가 있으면 자신을 파괴
        }

        _playerInput = GetComponent<PlayerInput>();
    }

    private void Start()
    {
        SetGlobalInputMap("Global");
    }

    public void UnPairDevices()
    {
        if(_playerInput != null)
        {
            _playerInput.user.UnpairDevices();
            PlayerInputEnable(false);
        }
    }

    public void PlayerInputEnable(bool flag)
    {
        _playerInput.enabled = flag;
    }    

    private void SetGlobalInputMap(string mapName)
    {
        _globalInputActionMap = _playerInput?.actions?.FindActionMap(mapName);
    }

    public void SetUIInputMap(string mapName)
    {
        _uiInputActionMap = _playerInput?.actions?.FindActionMap(mapName);
        if (_uiInputActionMap == null) return;

        //바인딩
        BindActionUI("OnKeyDown_UpArrow", OnKeyDown_UpArrow);
        BindActionUI("OnKeyDown_DownArrow", OnKeyDown_DownArrow);
        BindActionUI("OnKeyDown_Enter", OnKeyDown_Enter);
        BindActionUI("OnkeyDown_IKey", OnKeyDown_IKey);

        _uiInputActionMap.Disable();

    }

    public void SetCharacterInputMap(string mapName)
    {
        _characterInputActionMap = _playerInput?.actions?.FindActionMap(mapName);
        if (_characterInputActionMap == null) return;

        //바인딩
        BindActionCharacter("Scroll", OnMouseScroll);
        BindActionCharacter("Move", OnMove);
        BindActionCharacter("Sprint", OnSprint);
        BindActionCharacter("Jump", OnJump);
        BindActionCharacter("AimToggle", OnAimToggle);
        BindActionCharacter("Look", OnLook);
        BindActionCharacter("Dodge", OnDodge);
        BindActionCharacter("NormalAttack", OnNormalAttack);
        BindActionCharacter("HeavyAttack", OnHeavyAttack);

        BindActionCharacter("Interaction", OnInteraction);

        BindActionCharacter("OnkeyDown_IKey", OnKeyDown_IKey);
        

        _characterInputActionMap.Disable();

    }

    //매핑용 함수
    private void BindActionUI(string actionName, Action<InputAction.CallbackContext> callback)
    {
        InputAction action = _uiInputActionMap.FindAction(actionName);
        if (action != null)
        {
            action.performed -= callback;
            action.canceled -= callback;
            action.started -= callback;

            action.performed += callback;
            action.canceled += callback;
            action.started += callback;
        }
    }
    private void BindActionCharacter(string actionName, Action<InputAction.CallbackContext> callback)
    {
        InputAction action = _characterInputActionMap.FindAction(actionName);
        if (action != null)
        {
            action.performed -= callback;
            action.canceled -= callback;
            action.started -= callback;

            action.performed += callback;
            action.canceled += callback;
            action.started += callback;
        }
    }

    public void ActiveOnlyOneActionMap(string actionMapName)
    {
        _playerInput.SwitchCurrentActionMap(actionMapName);
    }

    #region 캐릭터 조작
    private void OnMouseScroll(InputAction.CallbackContext ctx)
    {
        Vector2 scroll = ctx.ReadValue<Vector2>();
        OnMouseScrollEvent?.Invoke(scroll.y);
    }

    private void OnMove(InputAction.CallbackContext ctx)
    {
        Vector2 move = ctx.ReadValue<Vector2>();
        OnMoveEvent?.Invoke(move);
    }

    private void OnSprint(InputAction.CallbackContext ctx)
    {
        if(ctx.performed)
        {
            OnSprintEvent?.Invoke(InputState.Performing);
        } 

        if(ctx.canceled)
        {
            OnSprintEvent?.Invoke(InputState.Canceled);
        }
    }

    private void OnJump(InputAction.CallbackContext ctx)
    {
        if(ctx.started)
        {
            OnJumpEvent?.Invoke(InputState.Started);
        }

        if (ctx.canceled)
        {
            OnJumpEvent?.Invoke(InputState.Canceled);
        }
    }
    private void OnAimToggle(InputAction.CallbackContext ctx)
    {
        if (ctx.started)
        {
            OnAimToggleEvent?.Invoke(InputState.Started);
        }
    }
    private void OnLook(InputAction.CallbackContext ctx)
    {
        Vector2 look = ctx.ReadValue<Vector2>();
        OnLookEvent?.Invoke(look);
    }

    private void OnDodge(InputAction.CallbackContext ctx)
    {
        if(ctx.started)
        {
            OnDodgeEvent?.Invoke(InputState.Started);
        }
    }

    private void OnNormalAttack(InputAction.CallbackContext ctx)
    {
        OnNormalAttackEvent?.Invoke();
    }

    private void OnHeavyAttack(InputAction.CallbackContext ctx)
    {
        OnHeavyAttackEvent?.Invoke();
    }

    private void OnInteraction(InputAction.CallbackContext ctx)
    {
        if (ctx.started)
            OnInteractionEvent?.Invoke();
    }
    #endregion

    #region 키별 조작
    private void OnKeyDown_UpArrow(InputAction.CallbackContext ctx)
    {
        if(ctx.started)
            OnKeyDown_UpArrowEvent?.Invoke();
    }

    private void OnKeyDown_DownArrow(InputAction.CallbackContext ctx)
    {
        if (ctx.started)
            OnKeyDown_DownArrowEvent?.Invoke();
    }

    private void OnKeyDown_Enter(InputAction.CallbackContext ctx)
    {
        if (ctx.started)
            OnKeyDown_EnterEvent?.Invoke();
    }

    private void OnKeyDown_IKey(InputAction.CallbackContext ctx)
    {
        if(ctx.started)
            OnKeyDown_IKeyEvent?.Invoke();
    }
    #endregion
}
