#include "wnd_render.h"
#include <wndbase.hpp>
#include <DirectXMath.h>
#include <windowsx.h>
#include <chrono>
#include <iostream>

#include "graphic.h"
#include "scene.h"

#include "shared_model.h"
#include "task_processer.h"
#include "renderer.h"
#include "tool.h"

#include "texture.h"

namespace {



}

class WndRender::Timer {
public:
    Timer() {
        m_lastTime = std::chrono::steady_clock::now();
    }
    float Tick() {
        std::chrono::steady_clock::time_point currentTime =
                std::chrono::steady_clock::now();
        std::chrono::duration<float> delta = currentTime - m_lastTime;
        m_lastTime = currentTime;
        return delta.count(); // 秒
    }

private:
    std::chrono::steady_clock::time_point m_lastTime;

};

//= public
WndRender::WndRender() = default;

WndRender::~WndRender() = default;

LRESULT WndRender::WndProc(UINT msg, WPARAM wparam, LPARAM lparam) {
    switch (msg) {
    case WM_DESTROY: {
        PostQuitMessage(0);
        return 0;
    }
    case WM_SIZE: {
        if (wparam != SIZE_MINIMIZED) {
            const UINT w = LOWORD(lparam);
            const UINT h = HIWORD(lparam);
            if (m_graphic) m_graphic->ResizeTheWinodw(w, h);
            if (m_scene)
                m_scene->SetCameraAspectRatio(
                    static_cast<float>(w) / static_cast<float>(h));
        }
        return 0;
    }
    case WM_CREATE: {
        if (!On_WM_CREATE(m_hwnd)) return -1;
        return 0;
    }
    case WM_RBUTTONDOWN: {
        m_lastMousePos.x = static_cast<int>(LOWORD(lparam));
        m_lastMousePos.y = static_cast<int>(HIWORD(lparam));
        SetCapture(m_hwnd);
        return 0;
    }
    case WM_RBUTTONUP: {
        ReleaseCapture();
        return 0;
    }
    case WM_MOUSEMOVE: {
        if (wparam & MK_RBUTTON) {
            int curx = GET_X_LPARAM(lparam);
            int cury = GET_Y_LPARAM(lparam);

            float dx = static_cast<float>(curx - m_lastMousePos.x);
            float dy = static_cast<float>(m_lastMousePos.y - cury);
            m_lastMousePos.x = curx;
            m_lastMousePos.y = cury;

            const Scene::SceneState *state = m_scene->GetSceneState();

            m_scene->SetCameraYaw(state->yaw + dx * 0.002f);
            m_scene->SetCameraPitch(state->pitch + dy * 0.002f);
        }
        return 0;
    }
    case WM_KEYDOWN: {
        bool notDown = (lparam & (1 << 30)) == 0;
        switch (wparam) {
        case 'W':
            if (notDown) m_moveKeyVector.z += 1;
            break;
        case 'A':
            if (notDown) m_moveKeyVector.x -= 1;
            break;
        case 'S':
            if (notDown) m_moveKeyVector.z -= 1;
            break;
        case 'D':
            if (notDown) m_moveKeyVector.x += 1;
            break;
        case 'E':
            if (notDown) m_moveKeyVector.y -= 1;
            break;
        case 'Q':
            if (notDown) m_moveKeyVector.y += 1;
            break;
        default: break;
        }
        return 0;
    }
    case WM_KEYUP: {
        switch (wparam) {
        case 'W':
            m_moveKeyVector.z -= 1;
            break;
        case 'A':
            m_moveKeyVector.x += 1;
            break;
        case 'S':
            m_moveKeyVector.z += 1;
            break;
        case 'D':
            m_moveKeyVector.x -= 1;
            break;
        case 'E':
            m_moveKeyVector.y += 1;
            break;
        case 'Q':
            m_moveKeyVector.y -= 1;
            break;
        default: break;
        }
        return 0;
    }
    default: return DefWindowProc(m_hwnd, msg, wparam, lparam);
    }
}

PCWSTR WndRender::CLASSNAME() { return L"WndRender"; }

//--= 每帧更新,被 WndBase call
void WndRender::UpdateWnd() const {
    using namespace DirectX;
    float tick = m_timer->Tick();

    // 读取指令
    ProcessTasks(m_graphic.get(), m_scene.get());

    // 渲染
    if (m_graphic) {
        // std::cout << std::fixed << "time(ms) = " << tick * 1000 <<
        //         "; fps = " << std::setprecision(0) << 1.0f / tick << std::endl;

        // 设置 Scene 的相机状态
        if (m_moveKeyVector.x != 0 || m_moveKeyVector.y != 0 || m_moveKeyVector.z != 0) {
            XMVECTOR dir = XMVector3Normalize(XMLoadSInt3(&m_moveKeyVector));
            XMFLOAT3 d{};
            XMStoreFloat3(&d, dir);
            m_scene->MoveCameraPos(d, tick);
        }

        try {
            m_renderer->RenderFrame(*m_scene);
        } catch (std::exception &e) {
            auto what = Z::u8_to_wstring(e.what());
            MessageBoxW(m_hwnd, what.c_str(), L"WndRender Update",MB_OK);
        }
    }
}

//= protected
bool WndRender::EDGEMODE() { return true; }

//= private
bool WndRender::On_WM_CREATE(HWND hwnd) {
    try {
        // 初始化 Graphic
        m_graphic = std::make_unique<Graphic>();
        if (!m_graphic->Init(m_hwnd))return false;

        // 初始化 Scene
        m_scene = std::make_unique<Scene>(*m_graphic->GetDevice());

        // 初始化 Resource (TexSampler等)
        if (!TexSampler::S_InitOnWmCreate(hwnd, m_graphic->GetDevice())) return false;
        if (!Texture2D::S_InitOnWmCreate(hwnd, m_graphic->GetDevice()))return false;

        // 初始化 Timer
        m_timer = std::make_unique<Timer>();

        // 初始化 Renderer
        m_renderer = std::make_unique<Renderer>(*m_graphic);

        std::cout << "初始化成功" << std::endl;

    } catch (std::exception &e) {
        auto what = Z::u8_to_wstring(e.what());
        MessageBoxW(m_hwnd, what.c_str(), L"WndRender CREATE",MB_OK);
        return false;
    }
    b_InitOver.store(true, std::memory_order::release);
    return true;
}











//
