using UnityEngine;
using System;
using UnityEngine.InputSystem;

/// <summary>
/// Централизованный ввод на основе New Input System.
/// Singleton, DontDestroyOnLoad.
/// Биндинги сохраняются в PlayerPrefs автоматически при изменении.
/// </summary>
public class PlayerInput : MonoBehaviour
{
    public static PlayerInput Instance { get; private set; }

    // ── Ссылка на InputActionAsset ────────────────────────────────────────────
    [Tooltip("Назначьте Assets/Input/PlayerControls.inputactions")]
    public InputActionAsset actions;

    // ── Непрерывные значения ──────────────────────────────────────────────────
    public Vector2 MoveInput { get; private set; }
    public Vector2 LookInput { get; private set; }
    public bool    Crouch    { get; private set; }
    public bool    Run       { get; private set; }

    // ── Дискретные события ────────────────────────────────────────────────────
    public event Action       OnToggleInventory;
    public event Action       OnDropPressed;
    public event Action       OnPickupPressed;
    public event Action       OnJumpPressed;
    public event Action<int>  OnHotbarSelect;

    // ── Включение/выключение gameplay-ввода (инвентарь открыт) ───────────────
    public bool Enabled
    {
        get  => _gameplayMap != null && _gameplayMap.enabled;
        set
        {
            if (_gameplayMap == null) return;
            if (value) _gameplayMap.Enable();
            else       _gameplayMap.Disable();
        }
    }

    // ── Приватные поля ────────────────────────────────────────────────────────
    private InputActionMap _gameplayMap;
    private InputActionMap _uiMap;
    private const string   BINDINGS_PREF_KEY = "PlayerBindings_v1";

    // ── Lifecycle ─────────────────────────────────────────────────────────────
    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
            return;
        }

        if (actions == null)
        {
            actions = Resources.Load<InputActionAsset>("PlayerControls");
            if (actions == null)
            {
                Debug.LogError("[PlayerInput] PlayerControls.inputactions не назначен и не найден в Resources!");
                return;
            }
        }

        // Создаём рабочую копию чтобы не менять оригинальный asset
        actions = Instantiate(actions);

        // Загрузить сохранённые биндинги
        var saved = PlayerPrefs.GetString(BINDINGS_PREF_KEY, "");
        if (!string.IsNullOrEmpty(saved))
            actions.LoadBindingOverridesFromJson(saved);

        _gameplayMap = actions.FindActionMap("Gameplay", throwIfNotFound: true);
        _uiMap       = actions.FindActionMap("UI",       throwIfNotFound: true);

        // Подписка: дискретные кнопки
        _gameplayMap["Jump"].performed    += _ => OnJumpPressed?.Invoke();
        _gameplayMap["Pickup"].performed  += _ => OnPickupPressed?.Invoke();
        _gameplayMap["Drop"].performed    += _ => OnDropPressed?.Invoke();

        // UI map всегда активна — нет double-fire бага
        _uiMap["ToggleInventory"].performed += _ => OnToggleInventory?.Invoke();
        _uiMap["CloseInventory"].performed  += _ => OnToggleInventory?.Invoke();

        for (int i = 0; i < 9; i++)
        {
            int idx = i;
            _gameplayMap[$"Hotbar{idx}"].performed += _ => OnHotbarSelect?.Invoke(idx);
        }

        _gameplayMap.Enable();
        _uiMap.Enable();
    }

    void OnDestroy()
    {
        _gameplayMap?.Disable();
        _uiMap?.Disable();
    }

    void Update()
    {
        if (_gameplayMap == null || !_gameplayMap.enabled) return;

        MoveInput = _gameplayMap["Move"].ReadValue<Vector2>();
        LookInput = _gameplayMap["Look"].ReadValue<Vector2>();
        Crouch    = _gameplayMap["Crouch"].IsPressed();
        Run       = _gameplayMap["Run"].IsPressed();
    }

    // ── Сохранение/загрузка биндингов ────────────────────────────────────────

    [ContextMenu("Save Bindings")]
    public void SaveBindings()
    {
        if (actions == null) return;
        PlayerPrefs.SetString(BINDINGS_PREF_KEY, actions.SaveBindingOverridesAsJson());
        PlayerPrefs.Save();
        Debug.Log("[PlayerInput] Биндинги сохранены");
    }

    [ContextMenu("Reset Bindings to Defaults")]
    public void ResetBindings()
    {
        if (actions == null) return;
        foreach (var action in actions)
            action.RemoveAllBindingOverrides();
        PlayerPrefs.DeleteKey(BINDINGS_PREF_KEY);
        Debug.Log("[PlayerInput] Биндинги сброшены к умолчаниям");
    }

    /// <summary>
    /// Интерактивный ремаппинг. Передайте имя action, имя map и callback для UI.
    /// Пример: StartRebind("Jump", "Gameplay", () => UpdateUI());
    /// </summary>
    public void StartRebind(string actionName, string mapName, Action onComplete)
    {
        var map    = actions?.FindActionMap(mapName);
        var action = map?.FindAction(actionName);
        if (action == null)
        {
            Debug.LogWarning($"[PlayerInput] Действие '{actionName}' в map '{mapName}' не найдено");
            return;
        }

        action.Disable();
        action.PerformInteractiveRebinding()
              .WithControlsExcluding("<Mouse>/position")
              .WithControlsExcluding("<Mouse>/delta")
              .OnComplete(op =>
              {
                  op.Dispose();
                  action.Enable();
                  SaveBindings();
                  onComplete?.Invoke();
              })
              .Start();
    }

    /// <summary>
    /// Доступ к InputActionAsset для UI-ремаппинга и отображения текущих биндингов.
    /// </summary>
    public InputActionAsset GetActions() => actions;
}
