#include "../UIFramework.h"
#include "../../Backend/Font/FontManager.h"
#include <algorithm>
#define NOMINMAX
#include <windows.h>
#include <imm.h>
#pragma comment(lib, "imm32.lib")

static void SetImePos(int x, int y) {
    HWND hwnd = (HWND)RLGetWindowHandle();
    if (!hwnd) return;
    HIMC himc = ImmGetContext(hwnd);
    if (!himc) return;

    COMPOSITIONFORM cf = {};
    cf.dwStyle = CFS_POINT;
    cf.ptCurrentPos.x = x;
    cf.ptCurrentPos.y = y;
    ImmSetCompositionWindow(himc, &cf);

    CANDIDATEFORM candf = {};
    candf.dwIndex = 0;
    candf.dwStyle = CFS_CANDIDATEPOS;
    candf.ptCurrentPos.x = x;
    candf.ptCurrentPos.y = y;
    ImmSetCandidateWindow(himc, &candf);

    ImmReleaseContext(hwnd, himc);
}

void WidgetManager::UpdateImePosition(int x, int y) {
    SetImePos(x, y);
}

bool WidgetManager::Textbox(const char* id, RLRectangle rect, TextboxState* state) {
    (void)id;

    auto ws = BeginWidget(rect);
    auto* font = Font::Get();

    const float kPad = 6.0f;
    const int kFontSize = 16;
    const float kInnerW = rect.width - 2.0f * kPad;
    const float kTextStart = rect.x + kPad;

    // ── UTF-8 helpers ──────────────────────────────────────
    auto prevChar = [&](int off) -> int {
        if (off <= 0) return 0;
        int i = off - 1;
        while (i > 0 && (state->text[i] & 0xC0) == 0x80) i--;
        return i;
    };
    auto nextChar = [&](int off) -> int {
        int len = (int)state->text.size();
        if (off >= len) return len;
        int i = off + 1;
        while (i < len && (state->text[i] & 0xC0) == 0x80) i++;
        return i;
    };

    // Convert mouse X (screen space) to byte offset in text
    auto charAtX = [&](float mouseX, float scrollOff) -> int {
        float x = kTextStart - scrollOff;
        int pos = 0;
        while (pos < (int)state->text.size()) {
            int next = nextChar(pos);
            float w = font->MeasureText(state->text.substr(pos, next - pos).c_str(), kFontSize, 2).x;
            if (mouseX < x + w * 0.5f) break;
            x += w;
            pos = next;
        }
        return pos;
    };

    // ── Focus ──────────────────────────────────────────────
    // Click on textbox → activate; click elsewhere or other widget consumed → deactivate
    if (ws.clicked) {
        state->active = true;

        // Place cursor at click position, start potential selection
        float mouseX = (float)RLGetMouseX();
        // Compute scroll offset to determine actual text position at click time
        float preScrollOff = 0.0f;
        {
            float preCursorX = kTextStart;
            if (state->cursor > 0) {
                std::string before = state->text.substr(0, state->cursor);
                preCursorX += font->MeasureText(before.c_str(), kFontSize, 2).x;
            }
            float visibleRight = kTextStart + kInnerW;
            if (preCursorX > visibleRight - 4.0f)
                preScrollOff = preCursorX - visibleRight + 20.0f;
        }
        int clickPos = charAtX(mouseX, preScrollOff);
        state->cursor = clickPos;
        state->selectStart = clickPos;
        state->selectEnd = clickPos;
        state->selecting = true;
    } else if (m_ctx.IsMousePressConsumed() || (RLIsMouseButtonPressed(RL_E_MOUSE_BUTTON_LEFT) && !ws.hover)) {
        state->active = false;
        state->selecting = false;
        state->selectStart = state->selectEnd = state->cursor;
    }

    // ── Mouse drag selection ───────────────────────────────
    if (state->selecting && RLIsMouseButtonDown(RL_E_MOUSE_BUTTON_LEFT)) {
        // Need current scroll offset to map mouse X correctly
        float curCursorX = kTextStart;
        if (state->cursor > 0) {
            std::string before = state->text.substr(0, state->cursor);
            curCursorX += font->MeasureText(before.c_str(), kFontSize, 2).x;
        }
        float curScrollOff = 0.0f;
        float visibleRight = kTextStart + kInnerW;
        if (curCursorX > visibleRight - 4.0f)
            curScrollOff = curCursorX - visibleRight + 20.0f;

        float mouseX = (float)RLGetMouseX();
        int dragPos = charAtX(mouseX, curScrollOff);
        state->cursor = dragPos;
        state->selectEnd = dragPos;
    }
    if (RLIsMouseButtonReleased(RL_E_MOUSE_BUTTON_LEFT))
        state->selecting = false;

    // ── Keyboard ───────────────────────────────────────────
    bool changed = false;
    bool interacted = false;

    if (state->active) {
        int selMin = std::min(state->selectStart, state->selectEnd);
        int selMax = std::max(state->selectStart, state->selectEnd);
        bool hasSel = (selMin != selMax);

        bool shift = RLIsKeyDown(RL_E_KEY_LEFT_SHIFT) || RLIsKeyDown(RL_E_KEY_RIGHT_SHIFT);

        // ── Character input ───────────────────────────────
        int cp;
        while ((cp = RLGetCharPressed()) > 0) {
            if (cp < 32) continue;

            // Replace selection if any
            if (hasSel) {
                state->text.erase(selMin, selMax - selMin);
                state->cursor = selMin;
                state->selectStart = state->selectEnd = selMin;
                selMin = selMax = state->cursor;
                hasSel = false;
            }

            char utf8[5];
            int len = 0;
            if (cp < 0x80) {
                utf8[len++] = (char)cp;
            } else if (cp < 0x800) {
                utf8[len++] = (char)(0xC0 | (cp >> 6));
                utf8[len++] = (char)(0x80 | (cp & 0x3F));
            } else if (cp < 0x10000) {
                utf8[len++] = (char)(0xE0 | (cp >> 12));
                utf8[len++] = (char)(0x80 | ((cp >> 6) & 0x3F));
                utf8[len++] = (char)(0x80 | (cp & 0x3F));
            } else if (cp < 0x110000) {
                utf8[len++] = (char)(0xF0 | (cp >> 18));
                utf8[len++] = (char)(0x80 | ((cp >> 12) & 0x3F));
                utf8[len++] = (char)(0x80 | ((cp >> 6) & 0x3F));
                utf8[len++] = (char)(0x80 | (cp & 0x3F));
            }
            utf8[len] = '\0';
            state->text.insert(state->cursor, utf8);
            state->cursor += len;
            changed = true;
            interacted = true;
        }

        // ── Backspace ─────────────────────────────────────
        if (RLIsKeyPressed(RL_E_KEY_BACKSPACE) || RLIsKeyPressedRepeat(RL_E_KEY_BACKSPACE)) {
            if (hasSel) {
                state->text.erase(selMin, selMax - selMin);
                state->cursor = selMin;
                state->selectStart = state->selectEnd = selMin;
                hasSel = false;
                changed = true;
                interacted = true;
            } else if (state->cursor > 0) {
                int prev = prevChar(state->cursor);
                state->text.erase(prev, state->cursor - prev);
                state->cursor = prev;
                state->selectStart = state->selectEnd = prev;
                changed = true;
                interacted = true;
            }
        }

        // ── Delete ───────────────────────────────────────
        if (RLIsKeyPressed(RL_E_KEY_DELETE) || RLIsKeyPressedRepeat(RL_E_KEY_DELETE)) {
            if (hasSel) {
                state->text.erase(selMin, selMax - selMin);
                state->cursor = selMin;
                state->selectStart = state->selectEnd = selMin;
                hasSel = false;
                changed = true;
                interacted = true;
            } else if (state->cursor < (int)state->text.size()) {
                int nxt = nextChar(state->cursor);
                state->text.erase(state->cursor, nxt - state->cursor);
                changed = true;
                interacted = true;
            }
        }

        // ── Arrow keys ───────────────────────────────────
        if (RLIsKeyPressed(RL_E_KEY_LEFT) || RLIsKeyPressedRepeat(RL_E_KEY_LEFT)) {
            int prev = prevChar(state->cursor);
            state->cursor = prev;
            if (shift)  state->selectEnd = prev;
            else        state->selectStart = state->selectEnd = prev;
            interacted = true;
        }
        if (RLIsKeyPressed(RL_E_KEY_RIGHT) || RLIsKeyPressedRepeat(RL_E_KEY_RIGHT)) {
            int nxt = nextChar(state->cursor);
            state->cursor = nxt;
            if (shift)  state->selectEnd = nxt;
            else        state->selectStart = state->selectEnd = nxt;
            interacted = true;
        }

        // ── Home / End ───────────────────────────────────
        if (RLIsKeyPressed(RL_E_KEY_HOME)) {
            state->cursor = 0;
            if (shift)  state->selectEnd = 0;
            else        state->selectStart = state->selectEnd = 0;
            interacted = true;
        }
        if (RLIsKeyPressed(RL_E_KEY_END)) {
            int end = (int)state->text.size();
            state->cursor = end;
            if (shift)  state->selectEnd = end;
            else        state->selectStart = state->selectEnd = end;
            interacted = true;
        }

        // ── Ctrl shortcuts ───────────────────────────────
        bool ctrl = RLIsKeyDown(RL_E_KEY_LEFT_CONTROL) || RLIsKeyDown(RL_E_KEY_RIGHT_CONTROL);

        if (ctrl && RLIsKeyPressed(RL_E_KEY_A)) {
            // Select all
            state->selectStart = 0;
            state->selectEnd = (int)state->text.size();
            state->cursor = (int)state->text.size();
            interacted = true;
        }
        if (ctrl && RLIsKeyPressed(RL_E_KEY_C)) {
            // Copy
            if (hasSel) {
                std::string sel = state->text.substr(selMin, selMax - selMin);
                RLSetClipboardText(sel.c_str());
            }
        }
        if (ctrl && RLIsKeyPressed(RL_E_KEY_X)) {
            // Cut
            if (hasSel) {
                std::string sel = state->text.substr(selMin, selMax - selMin);
                RLSetClipboardText(sel.c_str());
                state->text.erase(selMin, selMax - selMin);
                state->cursor = selMin;
                state->selectStart = state->selectEnd = selMin;
                hasSel = false;
                changed = true;
                interacted = true;
            }
        }
        if (ctrl && RLIsKeyPressed(RL_E_KEY_V)) {
            // Paste
            const char* clip = RLGetClipboardText();
            if (clip && clip[0]) {
                if (hasSel) {
                    state->text.erase(selMin, selMax - selMin);
                    state->cursor = selMin;
                    state->selectStart = state->selectEnd = selMin;
                    selMin = selMax = state->cursor;
                    hasSel = false;
                }
                state->text.insert(state->cursor, clip);
                state->cursor += (int)strlen(clip);
                state->selectStart = state->selectEnd = state->cursor;
                changed = true;
                interacted = true;
            }
        }

        if (interacted)
            state->lastInputTime = RLGetTime();
    }

    // ── Render ────────────────────────────────────────────
    RLDrawRectangleLines(rect.x, rect.y, rect.width, rect.height, { 12, 12, 12, 255 });
    RLDrawRectangleLines(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2, RLColor{ 50, 50, 50, 255 });
    RLDrawRectangleLines(rect.x + 2, rect.y + 2, rect.width - 4, rect.height - 4, RLColor{ 16, 16, 16, 255 });
    RLDrawRectangle(rect.x + 3, rect.y + 3, rect.width - 6, rect.height - 6, RLColor{ 25, 25, 25, 255 });

    // Compute normalized selection range
    int selMin = std::min(state->selectStart, state->selectEnd);
    int selMax = std::max(state->selectStart, state->selectEnd);

    // Cursor X (before scroll offset)
    float cursorX = kTextStart;
    if (state->cursor > 0) {
        std::string before = state->text.substr(0, state->cursor);
        cursorX += font->MeasureText(before.c_str(), kFontSize, 2).x;
    }

    // Horizontal scroll to keep cursor visible
    float scrollOff = 0.0f;
    float visibleRight = kTextStart + kInnerW;
    if (cursorX > visibleRight - 4.0f)
        scrollOff = cursorX - visibleRight + 20.0f;
    if (cursorX - scrollOff < kTextStart)
        scrollOff = cursorX - kTextStart;

    float drawX = kTextStart - scrollOff;
    float textY = rect.y + (rect.height - kFontSize) / 2.0f;

    // IME composition window follows cursor
    if (state->active)
        WidgetManager::UpdateImePosition((int)(cursorX - scrollOff), (int)(textY + kFontSize));

    RLBeginScissorMode((int)(rect.x + kPad), (int)rect.y, (int)kInnerW, (int)rect.height);

    // ── Selection highlight ──────────────────────────────
    if (state->active && selMin != selMax) {
        float selX1 = drawX;
        if (selMin > 0) {
            std::string before = state->text.substr(0, selMin);
            selX1 += font->MeasureText(before.c_str(), kFontSize, 2).x;
        }
        std::string selText = state->text.substr(selMin, selMax - selMin);
        float selW = font->MeasureText(selText.c_str(), kFontSize, 2).x;

        RLDrawRectangle((int)selX1, (int)(textY + 1), (int)selW, kFontSize, { 50, 100, 200, 160 });
    }

    // ── Text color ───────────────────────────────────────
    RLColor textColor;
    if (state->active)
        textColor = { 220, 220, 220, 255 };
    else if (ws.hover)
        textColor = { 200, 200, 200, 255 };
    else
        textColor = { 160, 160, 160, 255 };

    // ── Draw text ────────────────────────────────────────
    if (!state->text.empty()) {
        if (state->password) {
            int charCount = 0;
            for (size_t i = 0; i < state->text.size(); ) {
                if ((state->text[i] & 0xC0) != 0x80) charCount++;
                i++;
            }
            std::string masked(charCount, '*');
            font->DrawTextEX(masked.c_str(), { drawX, textY }, kFontSize, textColor, 2);
        } else {
            font->DrawTextEX(state->text.c_str(), { drawX, textY }, kFontSize, textColor, 2);
        }
    }

    // ── Cursor blink ─────────────────────────────────────
    if (state->active && !state->selecting) {
        double elapsed = RLGetTime() - state->lastInputTime;
        bool show = (elapsed < 0.5) || (((int)(RLGetTime() * 2.0)) % 2) == 0;
        if (show)
            RLDrawRectangle((int)(cursorX - scrollOff), (int)(textY + 2), 1, kFontSize - 4, { 220, 220, 220, 255 });
    }

    RLEndScissorMode();

    return changed;
}

bool Framework::Textbox(const char* id, RLRectangle rect, TextboxState* state) {
    return WidgetManager::Get()->Textbox(id, rect, state);
}
