#include "game.h"

#include <chrono>
#include <format>
#include <iostream>
#include <SDL3/SDL.h>
#include <Windows.h>
#include "image.h"
#include "settings.h"


LRESULT WINAPI wnd_proc(HWND window, UINT msg, WPARAM w, LPARAM l) {
	switch(msg) {
	case WM_DESTROY:
		::PostQuitMessage(0);
		return 0;
	}
	return ::DefWindowProc(window, msg, w, l);
}

game::game() : _cursor(0) {
}

void play_logo(HWND window, image const* logo, image const* logo_slime);

void game::run() {
	settings settings;
	init(settings);
	auto title = std::wstring(settings.title.begin(), settings.title.end());

	auto instance = GetModuleHandle(0);
	auto wc = WNDCLASS{
		.lpfnWndProc = wnd_proc,
		.hInstance = instance,
		.lpszClassName = title.c_str(),
	};

	auto atom = RegisterClass(&wc);
	auto window = CreateWindow(
		wc.lpszClassName,
		title.c_str(),
		WS_POPUP,
		0,
		0,
		settings.size.x * settings.scale,
		settings.size.y * settings.scale,
		0,
		0,
		instance,
		0
	);

	ShowWindow(window, SW_SHOWNORMAL);
	ShowCursor(FALSE);

	play_logo(window, get<image>("_/logo.png"), get<image>("_/logo-slime.png"));

	auto window_image = image(settings.size * settings.scale);
	auto screen = image(settings.size);
	screen.clear(0xffdddd);


	
	auto last_second = std::chrono::steady_clock::now();
	auto frames_since_last_second = 0;

	std::chrono::duration<int32_t, std::nano> second(1000000000ll);
	auto frame_duration = second / settings.target_fps;
	auto last_frame = last_second;
	_fps = settings.target_fps; //just visually nicer

	auto running = true;
	while(running) {
		MSG msg;
		while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			switch(msg.message) {
			case WM_QUIT:
				running = false;
				break;
			case WM_MOUSEMOVE:
				_mouse_pos.x = LOWORD(msg.lParam) / settings.scale;
				_mouse_pos.y = HIWORD(msg.lParam) / settings.scale;
				break;
			}
		}

		auto now = std::chrono::steady_clock::now();
		if(now - last_second >= std::chrono::seconds(1)) {
			_fps = frames_since_last_second;
			std::cout << std::format("FPS: {:5} | mspf: {}", _fps, 1000.0 / _fps) << std::endl;
			frames_since_last_second = 0;
			last_second += std::chrono::seconds(1);
		}

		if(now - last_frame >= frame_duration) {
			update();
			render(screen);
			if(_cursor)
				screen.draw(_cursor, _mouse_pos);
			auto p = screen.raw_pointer();
			if(screen.bounds() != window_image.bounds()) {
				//window_image.draw_upscaled(&screen);
				std::vector<upscaler> scalers;
				//scalers.push_back(upscaler::scale3x);
				//scalers.push_back(upscaler::scale3x);
				scalers.push_back(upscaler::lcd3x);
				//scalers.push_back(upscaler::hatch3x);
				window_image.draw_upscaled(&screen, scalers);
				p = window_image.raw_pointer();
			}

			BITMAPINFOHEADER bi{ sizeof(bi) };
			bi.biWidth = window_image.size().x;
			bi.biHeight = -window_image.size().y;
			bi.biPlanes = 1;
			bi.biBitCount = 32;
			bi.biCompression = BI_RGB;

			auto dc = GetDC(window);
			SetDIBitsToDevice(
				dc,
				0,
				0, 
				window_image.size().x,
				window_image.size().y,
				0,
				0,
				0,
				window_image.size().y,
				p,
				(BITMAPINFO*)&bi, 
				DIB_RGB_COLORS
			);
			ReleaseDC(window, dc);
			++frames_since_last_second;
			last_frame += frame_duration;
		}
	}


}

void game::init(settings& settings) {

}

void game::render(image& target) {
	
}

void game::update() {

}

vec2i const& game::mouse_pos() const {
	return _mouse_pos;
}

void game::cursor(image const* cursor) {
	_cursor = cursor;
}

int game::fps() {
	return _fps;
}

void play_logo(HWND window, image const* logo, image const* logo_slime) {
	settings settings;
	auto window_image = image(settings.size * settings.scale);
	auto screen = image(settings.size);

	std::chrono::duration<int32_t, std::nano> second(1000000000ll);
	auto frame_duration = second / settings.target_fps;
	auto last_frame = std::chrono::steady_clock::now();

	int frames = 180;
	while(frames) {
		MSG msg;
		while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		auto now = std::chrono::steady_clock::now();

		if(now - last_frame >= frame_duration) {

			screen.clear(0x242424);
			screen.draw(logo, vec2i(0, min(-frames*12 + 1600, 0)));
			screen.draw(logo_slime, screen.size() - vec2i(34, 28));
			if(frames < 60 && frames >= 30)
				screen.blend_to(0x0, 2.0 - (frames / 30.0));
			if(frames < 30)
				screen.clear(0);
			auto p = screen.raw_pointer();
			window_image.draw_upscaled(&screen, upscaler::scale3x);


			BITMAPINFOHEADER bi{ sizeof(bi) };
			bi.biWidth = window_image.size().x;
			bi.biHeight = -window_image.size().y;
			bi.biPlanes = 1;
			bi.biBitCount = 32;
			bi.biCompression = BI_RGB;

			auto dc = GetDC(window);
			SetDIBitsToDevice(
				dc,
				0,
				0,
				window_image.size().x,
				window_image.size().y,
				0,
				0,
				0,
				window_image.size().y,
				window_image.raw_pointer(),
				(BITMAPINFO*)&bi,
				DIB_RGB_COLORS
			);
			ReleaseDC(window, dc);
			last_frame += frame_duration;
			--frames;
		}
	}
}
