#include "native_ui/overlay_window.hpp"

#include <algorithm>
#include <cmath>
#include <format>
#include <vector>

namespace poe2::ui {

namespace {

constexpr const wchar_t* WINDOW_CLASS_NAME = L"Poe2VisualToolOverlayClass";

LRESULT CALLBACK OverlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch (msg) {
        case WM_DESTROY:
            return 0;
        default:
            return DefWindowProcW(hwnd, msg, wParam, lParam);
    }
}

// Chuyển màu sang Premultiplied ARGB cho UpdateLayeredWindow
inline uint32_t MakePremultipliedArgb(Color c) noexcept {
    uint32_t a = c.a;
    uint32_t r = (static_cast<uint32_t>(c.r) * a) / 255;
    uint32_t g = (static_cast<uint32_t>(c.g) * a) / 255;
    uint32_t b = (static_cast<uint32_t>(c.b) * a) / 255;
    return (a << 24) | (r << 16) | (g << 8) | b;
}

} // namespace

OverlayWindow::OverlayWindow() = default;

OverlayWindow::~OverlayWindow() {
    Destroy();
}

bool OverlayWindow::Create(int width, int height) {
    width_ = std::max(width, 100);
    height_ = std::max(height, 100);

    HINSTANCE hInst = GetModuleHandleW(nullptr);

    WNDCLASSEXW wc = {0};
    wc.cbSize = sizeof(WNDCLASSEXW);
    wc.lpfnWndProc = OverlayWndProc;
    wc.hInstance = hInst;
    wc.lpszClassName = WINDOW_CLASS_NAME;
    wc.hCursor = LoadCursorW(nullptr, MAKEINTRESOURCEW(32512));
    RegisterClassExW(&wc);

    // Cửa sổ trong suốt tuyệt đối, không nhận click chuột làm phiền game (Click-through)
    DWORD exStyle = WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_LAYERED | WS_EX_NOACTIVATE;
    hwnd_ = CreateWindowExW(
        exStyle,
        WINDOW_CLASS_NAME,
        L"Poe2VisualTool Overlay",
        WS_POPUP,
        0, 0, width_, height_,
        nullptr, nullptr, hInst, nullptr
    );

    if (!hwnd_) {
        return false;
    }

    HDC hScreenDc = GetDC(hwnd_);
    hMemDc_ = CreateCompatibleDC(hScreenDc);
    ReleaseDC(hwnd_, hScreenDc);

    hFontNormal_ = CreateFontW(
        15, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
        DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
        CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI"
    );

    hFontBold_ = CreateFontW(
        15, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
        DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
        CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Segoe UI"
    );

    ResizeBuffer(width_, height_);

    // Hiển thị cửa sổ
    ShowWindow(hwnd_, SW_SHOWNOACTIVATE);
    UpdateWindow(hwnd_);

    return true;
}

void OverlayWindow::Destroy() {
    if (hMemDc_) {
        // Deselect font safely before deleting DC
        SelectObject(hMemDc_, GetStockObject(SYSTEM_FONT));
        if (hOldBitmap_) {
            SelectObject(hMemDc_, hOldBitmap_);
            hOldBitmap_ = nullptr;
        }
        DeleteDC(hMemDc_);
        hMemDc_ = nullptr;
    }

    if (hBitmap_) {
        DeleteObject(hBitmap_);
        hBitmap_ = nullptr;
        pixelBuffer_ = nullptr;
    }

    if (hFontNormal_) {
        DeleteObject(hFontNormal_);
        hFontNormal_ = nullptr;
    }

    if (hFontBold_) {
        DeleteObject(hFontBold_);
        hFontBold_ = nullptr;
    }

    if (hwnd_) {
        DestroyWindow(hwnd_);
        hwnd_ = nullptr;
    }
}

void OverlayWindow::ResizeBuffer(int width, int height) {
    if (width <= 0 || height <= 0) return;
    if (width == width_ && height == height_ && pixelBuffer_ != nullptr) return;

    if (hOldBitmap_) {
        SelectObject(hMemDc_, hOldBitmap_);
        hOldBitmap_ = nullptr;
    }
    if (hBitmap_) {
        DeleteObject(hBitmap_);
        hBitmap_ = nullptr;
        pixelBuffer_ = nullptr;
    }

    BITMAPINFO bmi = {0};
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = -height; // Top-down DIB
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;

    void* bits = nullptr;
    HBITMAP newBmp = CreateDIBSection(hMemDc_, &bmi, DIB_RGB_COLORS, &bits, nullptr, 0);
    if (!newBmp || !bits) {
        return;
    }

    width_ = width;
    height_ = height;
    hBitmap_ = newBmp;
    pixelBuffer_ = static_cast<uint32_t*>(bits);
    hOldBitmap_ = static_cast<HBITMAP>(SelectObject(hMemDc_, hBitmap_));
}

void OverlayWindow::SetStreamerMode(bool enabled) {
    streamerMode_ = enabled;
    if (!hwnd_) return;

    // WDA_EXCLUDEFROMCAPTURE (0x00000011) ẩn cửa sổ hoàn toàn khỏi OBS / Discord / Screen Capture
    const DWORD WDA_EXCLUDE_FROM_CAPTURE = 0x00000011;
    const DWORD WDA_CAPTURE_NONE = 0x00000000;
    BOOL res = SetWindowDisplayAffinity(hwnd_, enabled ? WDA_EXCLUDE_FROM_CAPTURE : WDA_CAPTURE_NONE);
    if (!res && enabled) {
        // Fallback cho phiên bản Windows cũ hơn build 19041
        SetWindowDisplayAffinity(hwnd_, WDA_MONITOR);
    }
}

bool OverlayWindow::FollowGameWindow(HWND hGame) {
    if (!hwnd_ || !hGame || !IsWindow(hGame)) return false;

    RECT rc = {0};
    if (GetClientRect(hGame, &rc)) {
        POINT pt = {rc.left, rc.top};
        ClientToScreen(hGame, &pt);
        int w = rc.right - rc.left;
        int h = rc.bottom - rc.top;

        if (w != width_ || h != height_) {
            ResizeBuffer(w, h);
        }

        posX_ = pt.x;
        posY_ = pt.y;

        SetWindowPos(hwnd_, HWND_TOPMOST, pt.x, pt.y, w, h, SWP_NOACTIVATE);
        return true;
    }
    return false;
}

void OverlayWindow::BeginFrame() {
    Clear(Color{0, 0, 0, 0});
}

void OverlayWindow::Clear(Color bgColor) {
    if (!pixelBuffer_) return;
    uint32_t val = MakePremultipliedArgb(bgColor);
    std::fill_n(pixelBuffer_, width_ * height_, val);
}

void OverlayWindow::DrawRect(const Rect& rect, Color fillColor, Color borderColor, int borderWidth) {
    if (!pixelBuffer_) return;

    int x0 = std::clamp(rect.x, 0, width_ - 1);
    int y0 = std::clamp(rect.y, 0, height_ - 1);
    int x1 = std::clamp(rect.x + rect.width, 0, width_ - 1);
    int y1 = std::clamp(rect.y + rect.height, 0, height_ - 1);

    if (x0 >= x1 || y0 >= y1) return;

    uint32_t fillVal = MakePremultipliedArgb(fillColor);
    uint32_t borderVal = MakePremultipliedArgb(borderColor);

    for (int y = y0; y <= y1; ++y) {
        uint32_t* row = pixelBuffer_ + (y * width_);
        bool isBorderY = (y < y0 + borderWidth) || (y > y1 - borderWidth);

        for (int x = x0; x <= x1; ++x) {
            bool isBorderX = (x < x0 + borderWidth) || (x > x1 - borderWidth);
            if (isBorderY || isBorderX) {
                row[x] = borderVal;
            } else if (fillColor.a > 0) {
                row[x] = fillVal;
            }
        }
    }
}

void OverlayWindow::DrawTextLine(int x, int y, std::string_view text, Color color, bool bold) {
    if (!hMemDc_ || text.empty() || x < 0 || y < 0 || x >= width_ || y >= height_) return;

    // Chuyển đổi UTF-8 sang UTF-16 Unicode hỗ trợ tiếng Việt có dấu và icon
    int wlen = MultiByteToWideChar(CP_UTF8, 0, text.data(), static_cast<int>(text.size()), nullptr, 0);
    if (wlen <= 0) return;
    std::wstring wstr(wlen, L'\0');
    MultiByteToWideChar(CP_UTF8, 0, text.data(), static_cast<int>(text.size()), wstr.data(), wlen);

    SelectObject(hMemDc_, bold ? hFontBold_ : hFontNormal_);
    SetBkMode(hMemDc_, TRANSPARENT);
    SetTextColor(hMemDc_, RGB(color.r, color.g, color.b));

    SIZE sz = {0};
    GetTextExtentPoint32W(hMemDc_, wstr.c_str(), static_cast<int>(wstr.size()), &sz);
    TextOutW(hMemDc_, x, y, wstr.c_str(), static_cast<int>(wstr.size()));

    // Khắc phục giới hạn GDI TextOut đặt Alpha = 0 trên bề mặt Layered Window:
    // Cập nhật giá trị alpha = color.a và Premultiplied Alpha chuẩn cho các pixel của ký tự vừa được vẽ
    int xEnd = std::min<int>(x + static_cast<int>(sz.cx), width_ - 1);
    int yEnd = std::min<int>(y + static_cast<int>(sz.cy), height_ - 1);

    const uint32_t a = color.a;
    for (int cy = y; cy <= yEnd; ++cy) {
        uint32_t* row = pixelBuffer_ + (cy * width_);
        for (int cx = x; cx <= xEnd; ++cx) {
            uint32_t px = row[cx];
            // Nếu pixel vừa được GDI vẽ (alpha == 0 nhưng có nét chữ)
            if ((px >> 24) == 0 && (px & 0x00FFFFFF) != 0) {
                uint32_t r = (static_cast<uint32_t>((px >> 16) & 0xFF) * a) / 255;
                uint32_t g = (static_cast<uint32_t>((px >> 8) & 0xFF) * a) / 255;
                uint32_t b = (static_cast<uint32_t>(px & 0xFF) * a) / 255;
                row[cx] = (a << 24) | (r << 16) | (g << 8) | b;
            }
        }
    }
}

void OverlayWindow::DrawCircle(int cx, int cy, int radius, Color color, bool fill) {
    if (!pixelBuffer_ || radius <= 0) return;

    int x0 = std::clamp(cx - radius, 0, width_ - 1);
    int y0 = std::clamp(cy - radius, 0, height_ - 1);
    int x1 = std::clamp(cx + radius, 0, width_ - 1);
    int y1 = std::clamp(cy + radius, 0, height_ - 1);

    uint32_t val = MakePremultipliedArgb(color);
    int r2 = radius * radius;
    int innerR2 = (radius - 2) * (radius - 2);

    for (int y = y0; y <= y1; ++y) {
        int dy = y - cy;
        uint32_t* row = pixelBuffer_ + (y * width_);
        for (int x = x0; x <= x1; ++x) {
            int dx = x - cx;
            int d2 = dx * dx + dy * dy;
            if (fill) {
                if (d2 <= r2) row[x] = val;
            } else {
                if (d2 <= r2 && d2 >= innerR2) row[x] = val;
            }
        }
    }
}

void OverlayWindow::EndFrame() {
    if (!hwnd_ || !hMemDc_ || !pixelBuffer_) return;

    POINT ptSrc = {0, 0};
    SIZE sizeWnd = {width_, height_};
    POINT ptDst = {posX_, posY_};
    BLENDFUNCTION blend = {0};
    blend.BlendOp = AC_SRC_OVER;
    blend.SourceConstantAlpha = 255;
    blend.AlphaFormat = AC_SRC_ALPHA;

    // Passing nullptr for hdcDst uses the default screen device context
    UpdateLayeredWindow(hwnd_, nullptr, &ptDst, &sizeWnd, hMemDc_, &ptSrc, 0, &blend, ULW_ALPHA);
}

void OverlayWindow::RenderTooltip(const TooltipLayout& layout) {
    if (layout.lines.empty()) return;

    // 1. Vẽ nền Tooltip
    DrawRect(layout.bounds, colors::DarkBg, layout.borderColor, 2);

    // 2. Vẽ từng dòng nội dung
    int textX = layout.bounds.x + 14;
    int textY = layout.bounds.y + 12;

    for (const auto& line : layout.lines) {
        DrawTextLine(textX, textY, line.text, line.color, line.isBold);
        textY += 22;
    }
}

void OverlayWindow::RenderRadar(const RadarLayout& layout) {
    // 1. Vòng tròn Radar ngoại vi
    DrawCircle(layout.center.x, layout.center.y, layout.radius, colors::GoldBorder, false);
    // Vòng mờ phụ 50%
    DrawCircle(layout.center.x, layout.center.y, layout.radius / 2, colors::SubduedText, false);

    // 2. Điểm tâm nhân vật
    DrawCircle(layout.center.x, layout.center.y, 4, colors::RewardGreen, true);

    // 3. Các điểm POI
    for (const auto& m : layout.markers) {
        DrawCircle(m.screenX, m.screenY, 5, m.color, true);
        if (!m.symbol.empty()) {
            DrawTextLine(m.screenX + 7, m.screenY - 8, m.symbol, m.color, true);
        }
    }
}

void OverlayWindow::RenderSettings(const SettingsPanelLayout& layout) {
    // 1. Nền bảng cài đặt
    DrawRect(layout.bounds, colors::DarkerBg, colors::GoldBorder, 2);

    int textX = layout.bounds.x + 20;
    int textY = layout.bounds.y + 16;

    // 2. Tiêu đề
    DrawTextLine(textX, textY, "POE2 VISUAL TOOL - BANG DIEU KHIEN 2026", colors::GoldBorder, true);
    textY += 26;

    // 3. Trạng thái bản quyền
    DrawTextLine(textX, textY, layout.statusText, layout.statusColor, true);

    // 4. Danh sách Toggles
    for (const auto& tog : layout.toggles) {
        // Hộp checkbox [X] hoặc [ ]
        Rect boxRect{tog.hitBox.x, tog.hitBox.y + 3, 16, 16};
        DrawRect(boxRect, colors::DarkBg, colors::GoldBorder, 1);
        if (tog.checked) {
            DrawTextLine(boxRect.x + 4, boxRect.y - 1, "X", colors::GreenSuccess, true);
        }
        DrawTextLine(tog.hitBox.x + 26, tog.hitBox.y + 2, tog.label, colors::White, false);
    }

    // 5. Nút Panic Restore khẩn cấp
    DrawRect(layout.panicButtonBox, colors::BrickRed, colors::White, 1);
    DrawTextLine(layout.panicButtonBox.x + 18, layout.panicButtonBox.y + 8, "⚡ HOAN NGUYEN (F12)", colors::White, true);

    // 6. Nút đổi ngôn ngữ
    DrawRect(layout.langButtonBox, colors::DarkBg, colors::GoldBorder, 1);
    DrawTextLine(layout.langButtonBox.x + 15, layout.langButtonBox.y + 8, "Ngon Ngu: VI / EN", colors::White, false);
}

} // namespace poe2::ui
