#include "WindowsShell.h"
#include "resource.h"
#include "ApplicationData.h"
#include "Util.h"

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <shellapi.h>
#include <commctrl.h>
#include <strsafe.h>

#include <iostream>

const UINT TRAY_ID = 420;
const UINT WMAPP_NOTIFYCALLBACK = WM_APP + 1;

extern DrawData* gDrawData;
extern ApplicationData* gAppData;
extern bool justDocked;
extern bool isHidden;

void initShell(DrawData& drawData)
{
	// Set window icon
	HINSTANCE instance = GetModuleHandle(NULL);
	LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1);
	HANDLE iconLarge = LoadImageW(instance, iconId, IMAGE_ICON, 64, 64, 0);
	HANDLE iconSmall = LoadImageW(instance, iconId, IMAGE_ICON, 32, 32, 0);
	SendMessage(drawData.window_handle, WM_SETICON, ICON_BIG, (LPARAM)iconLarge);
	SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL, (LPARAM)iconSmall);
	SendMessage(drawData.window_handle, WM_SETICON, ICON_SMALL2, (LPARAM)iconSmall);

	// Set tray icon
	NOTIFYICONDATA nid = { sizeof(nid) };
	nid.hWnd = drawData.window_handle;
	nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP;
	nid.uID = TRAY_ID;
	nid.uCallbackMessage = WMAPP_NOTIFYCALLBACK;

	HRESULT iconResult;
	iconResult = LoadIconMetric(instance, iconId, LIM_SMALL, &nid.hIcon);
	isError(iconResult, "Failed to load tray icon image: ");

	iconResult = LoadString(instance, IDS_STRING_TOOLTIP, nid.szTip, ARRAYSIZE(nid.szTip));
	isError(iconResult, "Failed to load tray icon text: ");

	Shell_NotifyIcon(NIM_ADD, &nid);

	nid.uVersion = NOTIFYICON_VERSION_4;
	Shell_NotifyIcon(NIM_SETVERSION, &nid);

	if (!SetWindowsHookEx(WH_CALLWNDPROC, trayIconEventHandler, instance, GetCurrentThreadId()))
	{
		std::cout << "Failed to hook tray icon events: " << std::hex << GetLastError() << std::endl;
	}

	// Setup Toasts
	if (!WinToast::isCompatible()) {
		OutputDebugString(L"Error, your system in not supported!\n");
	}
	WinToast::instance()->setAppName(L"AudioThingy");
	const auto aumi = WinToast::configureAUMI(L"asuro", L"audiothingy");
	WinToast::instance()->setAppUserModelId(aumi);
	if (!WinToast::instance()->initialize()) {
		OutputDebugString(L"Error, could not initialize the lib!\n");
	}
	
	// Set window minimize behavior
	glfwSetWindowIconifyCallback(drawData.window, [](GLFWwindow* window, int isIconified) {
		if (isIconified && gAppData->settings.docked)
		{
			glfwHideWindow(window);
		}
		isHidden = isIconified;
		});

	glfwSetWindowFocusCallback(drawData.window, [](GLFWwindow* window, int isFocused) {
		if (!isFocused && gAppData->settings.docked && !justDocked)
		{
			glfwIconifyWindow(window);
		}
		});
}

void showToastNotification(TimerToastHandler* handler, const wchar_t* title, const wchar_t* text, UINT64 expiresInMs)
{
	WinToastTemplate templ = WinToastTemplate(WinToastTemplate::ImageAndText01);
	templ.setScenario(WinToastTemplate::Scenario::Alarm);
	templ.setImagePath(L"E:\\Code\\AsuroImgui\\x64\\Debug\\kaiju.ico");
	templ.setTextField(title, WinToastTemplate::FirstLine);
	templ.setAttributionText(text);
	templ.addAction(L"Stop");
	templ.addAction(L"Dismiss");
	if (expiresInMs > 0)
	{
		templ.setExpiration(expiresInMs);
	}

	if (!WinToast::instance()->showToast(templ, handler))
	{
		OutputDebugString(L"Error: Could not launch toast!\n");
	}
}

void cleanupShell(DrawData& drawData)
{
	// Remove tray icon
	NOTIFYICONDATA nid = { sizeof(nid) };
	nid.hWnd = drawData.window_handle;
	nid.uID = TRAY_ID;
	Shell_NotifyIcon(NIM_DELETE, &nid);
}

LRESULT CALLBACK trayIconEventHandler(int code, WPARAM wParam, LPARAM lParam)
{
	if (code >= 0)
	{
		CWPSTRUCT* data = (CWPSTRUCT*)lParam;

		if (data->message == WMAPP_NOTIFYCALLBACK)
		{
			auto id = HIWORD(data->lParam);
			auto trayEvent = LOWORD(data->lParam);

			if (id == TRAY_ID && (trayEvent == WM_LBUTTONUP || trayEvent == WM_RBUTTONUP))
			{
				glfwShowWindow(gDrawData->window);
				glfwRestoreWindow(gDrawData->window);
			}
		}
	}

	return CallNextHookEx(NULL, code, wParam, lParam);
}

void TimerToastHandler::toastActivated() const
{
	glfwShowWindow(gDrawData->window);
	glfwRestoreWindow(gDrawData->window);
}

void TimerToastHandler::toastActivated(int actionIndex) const
{
	if (actionIndex == 0)
	{
		gAppData->timerData.isTimerActive = false;
	}
	else if (actionIndex == 1)
	{
		
	}
}

void TimerToastHandler::toastFailed() const
{
}

void TimerToastHandler::toastDismissed(WinToastDismissalReason state) const
{
}
