// DirectX11Win32LibApp1.cpp : Defines the entry point for the application.
//

#include "pch.h"
#include "App.h"
#include "TwitchInGames.h"

#define MAX_LOADSTRING 100

using namespace DirectX11App1;

// Global Variables:
HINSTANCE hInst; // current instance
WCHAR szTitle[MAX_LOADSTRING]; // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name

std::shared_ptr<DX::DeviceResources> deviceResources;
std::unique_ptr<Main> main;

// Forward declarations of functions included in this code module:
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, _In_ int nCmdShow) {
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

	// Initialize global strings
	LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadStringW(hInstance, IDC_DIRECTX11WIN32LIBAPP1, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if(!InitInstance(hInstance, nCmdShow)) {
		return FALSE;
	}

	HACCEL const hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_DIRECTX11WIN32LIBAPP1));

	// Main message loop:
	MSG msg;
	for(bool gotMessage; gotMessage= !!PeekMessage(&msg, nullptr, 0u, 0u, PM_REMOVE), msg.message != WM_QUIT;) {
		if(gotMessage) {
			if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
		} else {
			main->Update();

			if(main->Render()) {
				deviceResources->Present();
			}
		}
	}

	return static_cast<int>(msg.wParam);
}



//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
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_DIRECTX11WIN32LIBAPP1));
	wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
	wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
	wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_DIRECTX11WIN32LIBAPP1);
	wcex.lpszClassName = szWindowClass;
	wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassExW(&wcex);
}

//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
static BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) {
	hInst = hInstance; // Store instance handle in our global variable

	HWND const hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

	if(!hWnd) {
		return FALSE;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	return TRUE;
}

static bool OnCreate(HWND hwnd, LPCREATESTRUCT /*lpCreateStruct*/) {
	deviceResources= std::make_shared<DX::DeviceResources>();
	deviceResources->SetWindow(hwnd);
	main= std::make_unique<Main>(deviceResources);
	return true;
}

static void OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, UINT /*codeNotify*/) {
	// Parse the menu selections.
	switch(id) {
	case IDM_ABOUT:
		DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, About);
		break;
	case IDM_EXIT:
		DestroyWindow(hwnd);
		break;
	}
}

static void OnSize(HWND /*hwnd*/, UINT /*state*/, int cx, int cy) {
	deviceResources->SetLogicalSize(DX::SIZE_F{ static_cast<float>(cx), static_cast<float>(cy) });
	main->CreateWindowSizeDependentResources();
}

static TwitchInGames::ClientAuth clientAuth;

static void DoFlow2(HWND hwnd) {
	static TwitchInGames::string_t const clientId= _T("dviaxdls39mj44cdnei76mj2dlig33");
	TwitchInGames::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") }).share();
	auto fn= [result] {
		auto const token= result.get();
		main->authenticationToken= token;
		auto const user= TwitchInGames::User::FetchCurrent(clientId, token.c_str()).get();
		auto const emailAddress= user.Email;
		main->authenticationToken += emailAddress;
	};
	concurrency::create_task(fn);
}

static void OnChar(HWND hwnd, TCHAR ch, int cRepeat) {
	if(cRepeat == 1) {
		switch(ch) {
		case _T('c'):
			clientAuth.Cancel();
			break;
		case _T('1'):
			main->authenticationToken= main->PerformServerAuth();
			break;
		case _T('2'):
			DoFlow2(hwnd);
			break;
		}
	}
}

//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
	switch(message) {
		HANDLE_MSG(hWnd, WM_CREATE, OnCreate);
		HANDLE_MSG(hWnd, WM_COMMAND, OnCommand);
		HANDLE_MSG(hWnd, WM_SIZE, OnSize);
		HANDLE_MSG(hWnd, WM_CHAR, OnChar);
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for about box.
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;
}
