#include "pch.h"
#include "../../lib/Shared/TwitchInGames.h"
#include "App.h"

using namespace TwitchInGames;

LPCWSTR const szWindowClass= L"WIN32APP1";

static ATOM MyRegisterClass(HINSTANCE hInstance);
static BOOL InitInstance(HINSTANCE, int);
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE /*hPrevInstance*/, _In_ LPWSTR /*lpCmdLine*/, int nCmdShow) {
	MyRegisterClass(hInstance);
	if(!InitInstance(hInstance, nCmdShow)) {
		return FALSE;
	}
	MSG msg;
	HACCEL const hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32APP1));
	while(GetMessage(&msg, nullptr, 0, 0)) {
		if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return static_cast<int>(msg.wParam);
}

static ATOM MyRegisterClass(HINSTANCE hInstance) {
	WNDCLASSEXW wcex{};
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = WndProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32APP1));
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
	wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_WIN32APP1);
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
	return RegisterClassExW(&wcex);
}

static BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
	HWND const hWnd = CreateWindowW(szWindowClass, L"Win32App1", WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
	if(!hWnd) {
		return FALSE;
	}
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	return TRUE;
}

// This function is not invoked.  It is here to ensure the QueryableFuture<T>
// and Callback<T> types compile correctly.
void CheckMultithreadingOptions() {
	ServerAuth serverAuth;
	tstring state;
	auto task= QueryableFuture<tstring>(serverAuth.StartAuth(L"", L"", { L"" }, state));
	auto fn= [](tstring s, std::exception_ptr ex) {
		s, ex;
	};
	auto callback= Callback<tstring>(serverAuth.StartAuth(L"", L"", { L"" }, state), fn);
}

#include "FlowOne.inl"

static void DoFlow1(HWND hwnd) {
	auto token= DoFlow1();
	MessageBox(hwnd, token.c_str(), _T("Flow One"), MB_OK);
}

static ClientAuth clientAuth;
static tstring token;
static tstring emailAddress;
static std::future<void> task;

static void DoFlow2(HWND hwnd) {
	static string_t const clientId = _T("dviaxdls39mj44cdnei76mj2dlig33");
	string_t const redirectUri = MessageBox(hwnd, _T("Succeed?"), _T("Flow Two"), MB_YESNO) == IDYES ?
		_T("twig://twig.tv/auth") : _T("twig:fail");

	auto result= clientAuth.StartAuth(clientId, redirectUri, { _T("user:read:email") });
	auto const fn= [hwnd](auto result) {
		token= result.get();
		PostMessage(hwnd, WM_USER, 0, 0);
		auto user= User::FetchCurrent(clientId, token.c_str()).get();
		emailAddress= user.Email;
		PostMessage(hwnd, WM_USER, 0, ~0);
	};
	task= std::async(std::launch::async, fn, std::move(result));
}

static void OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, UINT /*codeNotify*/) {
	switch(id) {
	case ID_FILE_FLOW1:
		DoFlow1(hwnd);
		break;
	case ID_FILE_FLOW2:
		DoFlow2(hwnd);
		break;
	case ID_FILE_CANCELFLOW2:
		clientAuth.Cancel();
		break;
	case IDM_ABOUT:
		DialogBox(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, About);
		break;
	case IDM_EXIT:
		DestroyWindow(hwnd);
		break;
	}
}

static void OnPaint(HWND hwnd) {
	PAINTSTRUCT ps;
	HDC hdc = BeginPaint(hwnd, &ps);
	// TODO: Add any drawing code that uses hdc here...
	hdc;
	EndPaint(hwnd, &ps);
}

static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	switch(message) {
		HANDLE_MSG(hWnd, WM_COMMAND, OnCommand);
		HANDLE_MSG(hWnd, WM_PAINT, OnPaint);
	case WM_USER:
		if(lParam) {
			MessageBox(hWnd, emailAddress.c_str(), _T("Email Address"), MB_OK);
		} else {
			MessageBox(hWnd, token.c_str(), _T("Token"), MB_OK);
		}
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

static INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM /*lParam*/) {
	switch(message) {
	case WM_INITDIALOG:
		return TRUE;
	case WM_COMMAND:
		if(LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
			EndDialog(hDlg, LOWORD(wParam));
			return TRUE;
		}
		break;
	}
	return FALSE;
}
