#include "pch.h"
#include "platform_windows/windows_splash.h"
#include "platform_windows/windows_bootstrap_helpers.h"

#include "app.h"
#include "image.h"
#include "log.h"
#include "version.h"

#include "../resource.h"

#include <chrono>
#include <shellscalingapi.h>
#include <string>
#include <stop_token>

namespace {

constexpr UINT kSplashCloseMessage = WM_USER + 1;

HBITMAP image_to_hbitmap(const Image& img)
{
    BITMAPINFOHEADER bmih;
    memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
    bmih.biWidth = img.width;
    bmih.biHeight = img.height;
    bmih.biBitCount = 32;
    bmih.biCompression = BI_RGB;
    bmih.biSize = sizeof(BITMAPINFOHEADER);
    bmih.biPlanes = 1;
    BITMAPINFO* bmi = (BITMAPINFO*)&bmih;
    return CreateDIBitmap(GetDC(NULL), &bmih, CBM_INIT, img.data(), bmi, DIB_RGB_COLORS);
}

LRESULT CALLBACK splash_proc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_INITDIALOG:
    {
        auto monitor = MonitorFromWindow(0, MONITOR_DEFAULTTOPRIMARY);
        auto x = unsigned{ 96 };
        auto y = unsigned{ 96 };
        if (pp::platform::windows::GetDpiForMonitor_fn)
            pp::platform::windows::GetDpiForMonitor_fn(monitor, MDT_EFFECTIVE_DPI, &x, &y);
        float z = (float)x / 96.f;

        static char base_path[MAX_PATH];
        GetCurrentDirectoryA(MAX_PATH, base_path);
        std::string path = std::string(base_path) + "\\data\\splash.jpg";
        Image img;
        img.load_file(path);
        img.flip();
        auto hbitmap = image_to_hbitmap(img.resize(512 * z, 200 * z));
        SendMessage(GetDlgItem(hWndDlg, IDC_STATIC_IMAGE), STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbitmap);
        SetDlgItemText(hWndDlg, IDC_STATIC_VERSION, g_version_number_w);

        RECT r;
        GetClientRect(hWndDlg, &r);
        MoveWindow(GetDlgItem(hWndDlg, IDC_STATIC_IMAGE), 0, 0, 512 * z, 200 * z, TRUE);
        SetWindowPos(hWndDlg, HWND_TOP, 0, 0, 512 * z, 200 * z, SWP_NOMOVE);

        HWND hWndVersion = GetDlgItem(hWndDlg, IDC_STATIC_VERSION);
        RECT rv;
        GetClientRect(hWndVersion, &rv);
        MoveWindow(hWndVersion, 0, 200 * z - (rv.bottom - rv.top), r.right - r.left, rv.bottom - rv.top, TRUE);

        return TRUE;
    }
    case kSplashCloseMessage:
        PostQuitMessage(0);
        return TRUE;
    }

    return DefWindowProc(hWndDlg, Msg, wParam, lParam);
}

}

namespace pp::platform::windows {

SplashScreen::SplashScreen(HINSTANCE hInst)
    : hInst_(hInst)
    , thread_([this](std::stop_token) { thread_main(); })
{
}

SplashScreen::~SplashScreen()
{
    dismiss();
}

void SplashScreen::dismiss()
{
    if (HWND dialog = dialog_.load(std::memory_order_acquire))
        SendMessage(dialog, kSplashCloseMessage, 0, 0);
    if (thread_.joinable())
        thread_.join();
}

void SplashScreen::thread_main()
{
    BT_SetTerminate();
    HWND dialog = CreateDialog(hInst_, MAKEINTRESOURCE(IDD_SPLASH), NULL, reinterpret_cast<DLGPROC>(splash_proc));
    dialog_.store(dialog, std::memory_order_release);
    if (!dialog)
        return;

    MSG msg;
    while (GetMessage(&msg, 0, 0, 0) > 0)
    {
        if (IsDialogMessage(dialog, &msg))
        {
            DispatchMessage(&msg);
            TranslateMessage(&msg);
        }
    }

    if (HWND dialog = dialog_.exchange(nullptr))
        DestroyWindow(dialog);
}

}
