#include "glfw_input.h"
#include <extra2d/utils/logger.h>
#include <cmath>

namespace extra2d {

// GLFW 按键到引擎按键的映射
static Key glfwToKey(int glfwKey) {
    switch (glfwKey) {
        // 字母键
        case GLFW_KEY_A: return Key::A;
        case GLFW_KEY_B: return Key::B;
        case GLFW_KEY_C: return Key::C;
        case GLFW_KEY_D: return Key::D;
        case GLFW_KEY_E: return Key::E;
        case GLFW_KEY_F: return Key::F;
        case GLFW_KEY_G: return Key::G;
        case GLFW_KEY_H: return Key::H;
        case GLFW_KEY_I: return Key::I;
        case GLFW_KEY_J: return Key::J;
        case GLFW_KEY_K: return Key::K;
        case GLFW_KEY_L: return Key::L;
        case GLFW_KEY_M: return Key::M;
        case GLFW_KEY_N: return Key::N;
        case GLFW_KEY_O: return Key::O;
        case GLFW_KEY_P: return Key::P;
        case GLFW_KEY_Q: return Key::Q;
        case GLFW_KEY_R: return Key::R;
        case GLFW_KEY_S: return Key::S;
        case GLFW_KEY_T: return Key::T;
        case GLFW_KEY_U: return Key::U;
        case GLFW_KEY_V: return Key::V;
        case GLFW_KEY_W: return Key::W;
        case GLFW_KEY_X: return Key::X;
        case GLFW_KEY_Y: return Key::Y;
        case GLFW_KEY_Z: return Key::Z;
        
        // 数字键
        case GLFW_KEY_0: return Key::Num0;
        case GLFW_KEY_1: return Key::Num1;
        case GLFW_KEY_2: return Key::Num2;
        case GLFW_KEY_3: return Key::Num3;
        case GLFW_KEY_4: return Key::Num4;
        case GLFW_KEY_5: return Key::Num5;
        case GLFW_KEY_6: return Key::Num6;
        case GLFW_KEY_7: return Key::Num7;
        case GLFW_KEY_8: return Key::Num8;
        case GLFW_KEY_9: return Key::Num9;
        
        // 功能键
        case GLFW_KEY_F1: return Key::F1;
        case GLFW_KEY_F2: return Key::F2;
        case GLFW_KEY_F3: return Key::F3;
        case GLFW_KEY_F4: return Key::F4;
        case GLFW_KEY_F5: return Key::F5;
        case GLFW_KEY_F6: return Key::F6;
        case GLFW_KEY_F7: return Key::F7;
        case GLFW_KEY_F8: return Key::F8;
        case GLFW_KEY_F9: return Key::F9;
        case GLFW_KEY_F10: return Key::F10;
        case GLFW_KEY_F11: return Key::F11;
        case GLFW_KEY_F12: return Key::F12;
        
        // 特殊键
        case GLFW_KEY_SPACE: return Key::Space;
        case GLFW_KEY_ENTER: return Key::Enter;
        case GLFW_KEY_ESCAPE: return Key::Escape;
        case GLFW_KEY_TAB: return Key::Tab;
        case GLFW_KEY_BACKSPACE: return Key::Backspace;
        case GLFW_KEY_INSERT: return Key::Insert;
        case GLFW_KEY_DELETE: return Key::Delete;
        case GLFW_KEY_HOME: return Key::Home;
        case GLFW_KEY_END: return Key::End;
        case GLFW_KEY_PAGE_UP: return Key::PageUp;
        case GLFW_KEY_PAGE_DOWN: return Key::PageDown;
        
        // 方向键
        case GLFW_KEY_UP: return Key::Up;
        case GLFW_KEY_DOWN: return Key::Down;
        case GLFW_KEY_LEFT: return Key::Left;
        case GLFW_KEY_RIGHT: return Key::Right;
        
        // 修饰键
        case GLFW_KEY_LEFT_SHIFT: return Key::LShift;
        case GLFW_KEY_RIGHT_SHIFT: return Key::RShift;
        case GLFW_KEY_LEFT_CONTROL: return Key::LCtrl;
        case GLFW_KEY_RIGHT_CONTROL: return Key::RCtrl;
        case GLFW_KEY_LEFT_ALT: return Key::LAlt;
        case GLFW_KEY_RIGHT_ALT: return Key::RAlt;
        
        // 锁定键
        case GLFW_KEY_CAPS_LOCK: return Key::CapsLock;
        case GLFW_KEY_NUM_LOCK: return Key::NumLock;
        case GLFW_KEY_SCROLL_LOCK: return Key::ScrollLock;
        
        default: return Key::None;
    }
}

GLFWInput::GLFWInput() {
    keyCurrent_.fill(false);
    keyPrevious_.fill(false);
    mouseCurrent_.fill(false);
    mousePrevious_.fill(false);
    gamepadCurrent_.fill(false);
    gamepadPrevious_.fill(false);
}

GLFWInput::~GLFWInput() {
    shutdown();
}

void GLFWInput::init() {
    E2D_LOG_INFO("GLFWInput initialized");
    openGamepad();
}

void GLFWInput::shutdown() {
    closeGamepad();
    E2D_LOG_INFO("GLFWInput shutdown");
}

void GLFWInput::update() {
    // 保存上一帧状态
    keyPrevious_ = keyCurrent_;
    mousePrevious_ = mouseCurrent_;
    gamepadPrevious_ = gamepadCurrent_;
    
    // 重置增量
    scrollDelta_ = 0.0f;
    mouseDelta_ = Vec2{0.0f, 0.0f};
    
    // 更新游戏手柄
    updateGamepad();
    
    // 更新键盘状态（通过轮询 GLFW）
    if (window_) {
        for (int i = GLFW_KEY_SPACE; i <= GLFW_KEY_LAST; ++i) {
            Key key = glfwToKey(i);
            if (key != Key::None) {
                int state = glfwGetKey(window_, i);
                keyCurrent_[static_cast<size_t>(key)] = (state == GLFW_PRESS);
            }
        }
        
        // 更新鼠标按钮状态
        for (int i = 0; i < static_cast<int>(Mouse::Count); ++i) {
            int glfwButton = GLFW_MOUSE_BUTTON_1 + i;
            if (glfwButton <= GLFW_MOUSE_BUTTON_LAST) {
                int state = glfwGetMouseButton(window_, glfwButton);
                mouseCurrent_[i] = (state == GLFW_PRESS);
            }
        }
        
        // 获取鼠标位置
        double x, y;
        glfwGetCursorPos(window_, &x, &y);
        mousePos_ = Vec2{static_cast<float>(x), static_cast<float>(y)};
    }
}

bool GLFWInput::down(Key key) const {
    size_t idx = static_cast<size_t>(key);
    if (idx < keyCurrent_.size()) {
        return keyCurrent_[idx];
    }
    return false;
}

bool GLFWInput::pressed(Key key) const {
    size_t idx = static_cast<size_t>(key);
    if (idx < keyCurrent_.size()) {
        return keyCurrent_[idx] && !keyPrevious_[idx];
    }
    return false;
}

bool GLFWInput::released(Key key) const {
    size_t idx = static_cast<size_t>(key);
    if (idx < keyCurrent_.size()) {
        return !keyCurrent_[idx] && keyPrevious_[idx];
    }
    return false;
}

bool GLFWInput::down(Mouse btn) const {
    size_t idx = static_cast<size_t>(btn);
    if (idx < mouseCurrent_.size()) {
        return mouseCurrent_[idx];
    }
    return false;
}

bool GLFWInput::pressed(Mouse btn) const {
    size_t idx = static_cast<size_t>(btn);
    if (idx < mouseCurrent_.size()) {
        return mouseCurrent_[idx] && !mousePrevious_[idx];
    }
    return false;
}

bool GLFWInput::released(Mouse btn) const {
    size_t idx = static_cast<size_t>(btn);
    if (idx < mouseCurrent_.size()) {
        return !mouseCurrent_[idx] && mousePrevious_[idx];
    }
    return false;
}

Vec2 GLFWInput::mouse() const {
    return mousePos_;
}

Vec2 GLFWInput::mouseDelta() const {
    return mouseDelta_;
}

float GLFWInput::scroll() const {
    return scroll_;
}

float GLFWInput::scrollDelta() const {
    return scrollDelta_;
}

void GLFWInput::setMouse(const Vec2& pos) {
    if (window_) {
        glfwSetCursorPos(window_, pos.x, pos.y);
    }
}

bool GLFWInput::gamepad() const {
    return gamepadId_ != -1;
}

bool GLFWInput::down(Gamepad btn) const {
    size_t idx = static_cast<size_t>(btn);
    if (idx < gamepadCurrent_.size()) {
        return gamepadCurrent_[idx];
    }
    return false;
}

bool GLFWInput::pressed(Gamepad btn) const {
    size_t idx = static_cast<size_t>(btn);
    if (idx < gamepadCurrent_.size()) {
        return gamepadCurrent_[idx] && !gamepadPrevious_[idx];
    }
    return false;
}

bool GLFWInput::released(Gamepad btn) const {
    size_t idx = static_cast<size_t>(btn);
    if (idx < gamepadCurrent_.size()) {
        return !gamepadCurrent_[idx] && gamepadPrevious_[idx];
    }
    return false;
}

Vec2 GLFWInput::leftStick() const {
    return leftStick_;
}

Vec2 GLFWInput::rightStick() const {
    return rightStick_;
}

float GLFWInput::leftTrigger() const {
    return leftTrigger_;
}

float GLFWInput::rightTrigger() const {
    return rightTrigger_;
}

void GLFWInput::vibrate(float left, float right) {
    // GLFW 本身不支持震动，需要平台特定的代码
    // 这里可以扩展为使用平台特定的 API
    (void)left;
    (void)right;
}

bool GLFWInput::touching() const {
    return false;
}

int GLFWInput::touchCount() const {
    return 0;
}

Vec2 GLFWInput::touch(int index) const {
    (void)index;
    return Vec2{0.0f, 0.0f};
}

TouchPoint GLFWInput::touchPoint(int index) const {
    (void)index;
    return TouchPoint{};
}

// 事件处理函数
void GLFWInput::handleKeyEvent(int key, int scancode, int action, int mods) {
    (void)scancode;
    (void)mods;
    
    Key eKey = glfwToKey(key);
    if (eKey != Key::None) {
        size_t idx = static_cast<size_t>(eKey);
        if (action == GLFW_PRESS) {
            keyCurrent_[idx] = true;
        } else if (action == GLFW_RELEASE) {
            keyCurrent_[idx] = false;
        }
    }
}

void GLFWInput::handleMouseButtonEvent(int button, int action, int mods) {
    (void)mods;
    
    if (button >= GLFW_MOUSE_BUTTON_1 && button <= GLFW_MOUSE_BUTTON_LAST) {
        size_t idx = static_cast<size_t>(button - GLFW_MOUSE_BUTTON_1);
        if (idx < mouseCurrent_.size()) {
            if (action == GLFW_PRESS) {
                mouseCurrent_[idx] = true;
            } else if (action == GLFW_RELEASE) {
                mouseCurrent_[idx] = false;
            }
        }
    }
}

void GLFWInput::handleCursorPosEvent(double xpos, double ypos) {
    Vec2 newPos{static_cast<float>(xpos), static_cast<float>(ypos)};
    mouseDelta_ = newPos - mousePos_;
    mousePos_ = newPos;
}

void GLFWInput::handleScrollEvent(double xoffset, double yoffset) {
    (void)xoffset;
    scroll_ += static_cast<float>(yoffset);
    scrollDelta_ += static_cast<float>(yoffset);
}

void GLFWInput::handleJoystickEvent(int jid, int event) {
    if (event == GLFW_CONNECTED) {
        E2D_LOG_INFO("Gamepad connected: {}", jid);
        if (gamepadId_ == -1) {
            openGamepad();
        }
    } else if (event == GLFW_DISCONNECTED) {
        if (jid == gamepadId_) {
            E2D_LOG_INFO("Gamepad disconnected: {}", jid);
            closeGamepad();
        }
    }
}

void GLFWInput::updateGamepad() {
    if (gamepadId_ == -1) {
        return;
    }
    
    GLFWgamepadstate state;
    if (!glfwGetGamepadState(gamepadId_, &state)) {
        return;
    }
    
    // 更新按钮状态
    gamepadCurrent_[static_cast<size_t>(Gamepad::A)] = state.buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::B)] = state.buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::X)] = state.buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::Y)] = state.buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::Back)] = state.buttons[GLFW_GAMEPAD_BUTTON_BACK] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::Start)] = state.buttons[GLFW_GAMEPAD_BUTTON_START] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::LStick)] = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_THUMB] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::RStick)] = state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_THUMB] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::LB)] = state.buttons[GLFW_GAMEPAD_BUTTON_LEFT_BUMPER] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::RB)] = state.buttons[GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::DUp)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::DDown)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::DLeft)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::DRight)] = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_PRESS;
    gamepadCurrent_[static_cast<size_t>(Gamepad::Guide)] = state.buttons[GLFW_GAMEPAD_BUTTON_GUIDE] == GLFW_PRESS;
    
    // 更新摇杆值（应用死区）
    leftStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_X]);
    leftStick_.y = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_LEFT_Y]);
    rightStick_.x = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_X]);
    rightStick_.y = applyDeadzone(state.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y]);
    
    // 更新扳机值（范围 [0, 1]）
    leftTrigger_ = (state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1.0f) * 0.5f;
    rightTrigger_ = (state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1.0f) * 0.5f;
}

void GLFWInput::openGamepad() {
    for (int jid = GLFW_JOYSTICK_1; jid <= GLFW_JOYSTICK_LAST; ++jid) {
        if (glfwJoystickPresent(jid) && glfwJoystickIsGamepad(jid)) {
            gamepadId_ = jid;
            E2D_LOG_INFO("Gamepad opened: {}", glfwGetGamepadName(jid));
            return;
        }
    }
}

void GLFWInput::closeGamepad() {
    if (gamepadId_ != -1) {
        gamepadId_ = -1;
        gamepadCurrent_.fill(false);
        gamepadPrevious_.fill(false);
        leftStick_ = Vec2{0.0f, 0.0f};
        rightStick_ = Vec2{0.0f, 0.0f};
        leftTrigger_ = 0.0f;
        rightTrigger_ = 0.0f;
    }
}

float GLFWInput::applyDeadzone(float value) const {
    if (std::abs(value) < deadzone_) {
        return 0.0f;
    }
    float sign = value >= 0.0f ? 1.0f : -1.0f;
    return sign * (std::abs(value) - deadzone_) / (1.0f - deadzone_);
}

} // namespace extra2d
