#pragma once

#include <SDL3/SDL.h>
#include <unordered_map>
#include <functional>
#include <vector>
#include "../interfaces/IInputHandler.h"

/**
 * InputManager - Centralized input handling system
 * 
 * Responsibilities:
 * - Process SDL events and maintain input state
 * - Provide clean interface for input queries
 * - Handle keyboard and mouse input
 * - Support event handler registration
 * - Implement game-specific input logic (DAS/ARR)
 */
class InputManager : public IInputHandler {
public:
    // Event handler types
    using KeyHandler = std::function<void(SDL_Scancode key, bool pressed)>;
    using MouseButtonHandler = std::function<void(int button, bool pressed, float x, float y)>;
    using MouseMotionHandler = std::function<void(float x, float y, float deltaX, float deltaY)>;
    using WindowEventHandler = std::function<void(const SDL_WindowEvent& event)>;
    using QuitHandler = std::function<void()>;

    InputManager();
    ~InputManager() = default;

    // IInputHandler interface implementation
    bool processEvent(const SDL_Event& event) override;
    void update(double deltaTime) override;
    bool isKeyCurrentlyPressed(SDL_Scancode scancode) const override;
    bool isKeyJustPressed(SDL_Scancode scancode) const override;
    bool isKeyJustReleased(SDL_Scancode scancode) const override;
    bool isQuitRequested() const override;
    void reset() override;

    // Existing InputManager methods
    void processEvents();
    void update(float deltaTime);

    // Keyboard state queries
    bool isKeyPressed(SDL_Scancode key) const;      // True only on the frame key was pressed
    bool isKeyReleased(SDL_Scancode key) const;     // True only on the frame key was released  
    bool isKeyHeld(SDL_Scancode key) const;         // True while key is down

    // Mouse state queries
    bool isMouseButtonPressed(int button) const;
    bool isMouseButtonReleased(int button) const;
    bool isMouseButtonHeld(int button) const;
    void getMousePosition(float& x, float& y) const;
    void getMouseDelta(float& deltaX, float& deltaY) const;

    // Event handler registration
    void registerKeyHandler(KeyHandler handler);
    void registerMouseButtonHandler(MouseButtonHandler handler);
    void registerMouseMotionHandler(MouseMotionHandler handler);
    void registerWindowEventHandler(WindowEventHandler handler);
    void registerQuitHandler(QuitHandler handler);

    // Game-specific input utilities (DAS/ARR system for Tetris)
    struct DASState {
        bool isActive = false;
        float delayTimer = 0.0f;
        float repeatTimer = 0.0f;
        SDL_Scancode activeKey = SDL_SCANCODE_UNKNOWN;
    };

    void configureDAS(float delayMs, float repeatMs);
    bool checkDASMovement(SDL_Scancode leftKey, SDL_Scancode rightKey, int& direction);

    // Application control
    bool shouldQuit() const { return m_shouldQuit; }
    void requestQuit() { m_shouldQuit = true; }

private:
    // Input state tracking
    std::unordered_map<SDL_Scancode, bool> m_currentKeyState;
    std::unordered_map<SDL_Scancode, bool> m_previousKeyState;
    std::unordered_map<int, bool> m_currentMouseState;
    std::unordered_map<int, bool> m_previousMouseState;

    // Mouse position tracking
    float m_mouseX = 0.0f;
    float m_mouseY = 0.0f;
    float m_mouseDeltaX = 0.0f;
    float m_mouseDeltaY = 0.0f;

    // Event handlers
    std::vector<KeyHandler> m_keyHandlers;
    std::vector<MouseButtonHandler> m_mouseButtonHandlers;
    std::vector<MouseMotionHandler> m_mouseMotionHandlers;
    std::vector<WindowEventHandler> m_windowEventHandlers;
    std::vector<QuitHandler> m_quitHandlers;

    // Application state
    bool m_shouldQuit = false;

    // DAS/ARR system for Tetris-style movement
    DASState m_dasState;
    float m_dasDelay = 170.0f;    // Default DAS delay in ms
    float m_dasRepeat = 40.0f;    // Default ARR (Auto Repeat Rate) in ms

    // Helper methods
    void handleKeyEvent(const SDL_KeyboardEvent& event);
    void handleMouseButtonEvent(const SDL_MouseButtonEvent& event);
    void handleMouseMotionEvent(const SDL_MouseMotionEvent& event);
    void handleWindowEvent(const SDL_WindowEvent& event);
    void handleQuitEvent();
    void updateInputState();
    void updateDAS(float deltaTime);
    void resetDAS();
};
