#include <object/ui/uitextbox.hpp>
#include <renderer/renderer.hpp>

namespace Game::Object {

    UITextBox::UITextBox(const std::string& name, std::shared_ptr<Renderer::Font> font,
                         const Transform& transform, float x, float y, UITextboxConfig config)
        : Entity(name, font, transform), mX(x), mY(y), mConfig(config) { }

    void UITextBox::start() {
        mTransform.x = mX - mTex->getWidth()  * mTransform.adjustedScaleX() / 2.f;
        mTransform.y = mY - mTex->getHeight() * mTransform.adjustedScaleY() / 2.f;

        mBoxWidth  = static_cast<float>(mTex->getWidth())  * mTransform.adjustedScaleX();
        mBoxHeight = static_cast<float>(mTex->getHeight()) * mTransform.adjustedScaleY();

        if (mBoxWidth  < mConfig.minWidth)  mBoxWidth  = mConfig.minWidth;
        if (mBoxHeight < mConfig.minHeight) mBoxHeight = mConfig.minHeight;

        refreshVisualText();
    }

    void UITextBox::update(float deltaTime) {
        if (!mIsActive) return;

        if (Input::isMouseButtonJustPressed(SDL_BUTTON_LEFT)) {
            mIsFocused = isMouseInsideBox();
            mNeedsTextRefresh = true;
        }

        if (mIsFocused) {
            // Cursor blink
            mCursorTimer += deltaTime;
            if (mCursorTimer >= mConfig.cursorBlinkRate) {
                mCursorTimer   = 0.f;
                mCursorVisible = !mCursorVisible;
                mNeedsTextRefresh = true;
            }

            if (Input::isKeyJustPressed(SDL_SCANCODE_BACKSPACE) && !mText.empty()) {
                mText.pop_back();
                mNeedsTextRefresh = true;
            }

            if (Input::isKeyJustPressed(SDL_SCANCODE_RETURN) || Input::isKeyJustPressed(SDL_SCANCODE_KP_ENTER)) {
                mIsFocused    = false;
                mCursorTimer  = 0.f;
                mCursorVisible = true;
                mNeedsTextRefresh = true;
            }

            for (int key = 0; key < SDL_SCANCODE_COUNT; ++key) {
                SDL_Scancode scancode = static_cast<SDL_Scancode>(key);
                if (!Input::isKeyJustPressed(scancode)) continue;

                SDL_Keycode keycode = SDL_GetKeyFromScancode(scancode, SDL_GetModState(), true);
                if (keycode >= 32 && keycode <= 126) {
                    if (mConfig.maxLength == 0 || static_cast<int>(mText.size()) < mConfig.maxLength) {
                        mText.push_back(static_cast<char>(keycode));
                        mNeedsTextRefresh = true;
                    }
                }
            }
        }

        if (mNeedsTextRefresh) {
            refreshVisualText();
        }
    }

    void UITextBox::render(Game::Renderer::Renderer* renderer, Game::Renderer::RendererConfig config) {
        if (!mIsVisible) return;

        SDL_Renderer* r = renderer->getSDLRenderer();

        const float bx = mTransform.x - mConfig.paddingX - config.camX + config.screenW / 2.f;
        const float by = mTransform.y - mConfig.paddingY - config.camY + config.screenH / 2.f;
        const float bw = mBoxWidth + 2.f * mConfig.paddingX;
        const float bh = mBoxHeight + 2.f * mConfig.paddingY;
        const float t = mConfig.borderThickness;

        // Background
        SDL_SetRenderDrawBlendMode(r, SDL_BLENDMODE_BLEND);
        const SDL_Color& bg = mConfig.bgColor;
        SDL_SetRenderDrawColor(r, bg.r, bg.g, bg.b, bg.a);
        const SDL_FRect bgRect = {bx, by, bw, bh};
        SDL_RenderFillRect(r, &bgRect);

        // Border (4 filled rects for configurable thickness)
        const SDL_Color& bc = mIsFocused ? mConfig.focusedBorderColor : mConfig.borderColor;
        SDL_SetRenderDrawColor(r, bc.r, bc.g, bc.b, bc.a);
        const SDL_FRect borders[4] = {
            {bx,          by,          bw, t },  // top
            {bx,          by + bh - t, bw, t },  // bottom
            {bx,          by,          t,  bh},  // left
            {bx + bw - t, by,          t,  bh},  // right
        };
        SDL_RenderFillRects(r, borders, 4);

        // Text (or placeholder) via base render
        Entity::render(renderer, config);
    }

    void UITextBox::setText(const std::string& text) {
        mText = text;
        mNeedsTextRefresh = true;
        refreshVisualText();
    }

    std::string UITextBox::getText() const { return mText; }
    std::string UITextBox::getValue() const { return mText; }
    bool UITextBox::isFocused() const { return mIsFocused; }

    bool UITextBox::isMouseInsideBox() const {
        const float mouseX = Input::getMouseX();
        const float mouseY = Input::getMouseY();

        const float left = mTransform.x - mConfig.paddingX;
        const float right = left + mBoxWidth + 2.f * mConfig.paddingX;
        const float top = mTransform.y - mConfig.paddingY;
        const float bottom = top  + mBoxHeight + 2.f * mConfig.paddingY;

        return mouseX >= left && mouseX <= right && mouseY >= top && mouseY <= bottom;
    }

    void UITextBox::refreshVisualText() {
        const bool showPlaceholder = mText.empty() && !mIsFocused && !mConfig.placeholder.empty();

        SDL_Color color;
        std::string rendered;

        if (showPlaceholder) {
            color = mConfig.placeholderColor;
            rendered = mConfig.placeholder;
        } else {
            color = mIsFocused ? mConfig.focusedTextColor : mConfig.textColor;
            rendered = mText.empty() ? " " : mText;
            if (mIsFocused && mCursorVisible) {
                rendered += "_";
            }
        }

        std::dynamic_pointer_cast<Renderer::Font>(mTex)->build(color, rendered);
        mNeedsTextRefresh = false;
    }

}
