#include <windows.h>
#include <commctrl.h>    // For WC_TABCONTROL, TCITEM, TabCtrl_InsertItem
#include "control_ids.h" // For ID_TABCONTROL, ID_TABPAGE_BASE, NUM_TABS
#include "LiftoffWin32DesktopTestApp.h" // For hTab, hTabPages, oldTabPageWndProc, TabPageWndProc, CreateControlsForTab1, etc.

#include "framework.h"
#include "LiftoffInterstitialAds.h"
#include "UiUtilities.h"

#include <string>
#include <locale>
#include <codecvt>

/// <summary>
/// This file contains code that is used to create and manage the UI controls in the Win32 desktop test app.
/// For code examples that show how to use the Liftoff SDK, see LiftoffInterstitialAds.cpp and LiftoffMediation.cpp
/// </summary>
HWND hTab, hTabPages[NUM_TABS];
// Tab 1
HWND hLabelAppId, hEditAppId, hButtonInitialize, hButtonLoad, hButtonPlay, hButtonPlayInNewWindow, hPlacementsListBox, hButtonShowDataInExplorer;
// Tab 2 ("Options")
HWND hCheckBoxDisableASHWID;
HWND hLabelIncentivizedTitle, hEditIncentivizedTitle, hLabelIncentivizedBody, hEditIncentivizedBody, hLabelIncentivizedClose, hEditIncentivizedClose, hLabelIncentivizedContinue, hEditIncentivizedContinue;
HWND hLabelPositionX, hEditPositionX, hLabelPositionY, hEditPositionY;

// Tab 3 ("Debug")
HWND hProxyCheckbox, hProxyAddressLabel, hProxyAddressEdit, hProxyPortLabel, hProxyPortEdit, hWebView2DebugCheckbox;

HWND hEdits[2], hLabels[2], hCheckBoxes[2], hMultiLineEdit;

std::wstring GetWStringFromControl(HWND hParent, int controlId) {
	HWND hEdit = GetDlgItem(hParent, controlId);
	if (!hEdit) return L"";
	int len = GetWindowTextLengthW(hEdit);
	if (len <= 0) return L"";
	std::wstring buffer(len, L'\0');
	GetWindowTextW(hEdit, &buffer[0], len + 1);
	return buffer;
}

void CreateControlsForTab1(HWND hwnd) {
	hLabelAppId = CreateWindow(L"STATIC", L"App ID:", WS_VISIBLE | WS_CHILD,
		20, 20, 60, 20, hwnd, NULL, NULL, NULL);
	hEditAppId = CreateWindow(L"EDIT", L"59766ed3cc9b98e371000cbc", //L"5797949864c72d066f000097",
		WS_VISIBLE | WS_CHILD | WS_BORDER,
		100, 20, 300, 20, hwnd, (HMENU)ID_EDIT_APP_ID, NULL, NULL);

	hButtonInitialize = CreateWindow(L"BUTTON", L"Start Vungle", WS_VISIBLE | WS_CHILD,
		20, 60, 100, 30, hwnd, (HMENU)ID_BUTTON_INITIALIZE, NULL, NULL);
	hButtonLoad = CreateWindow(L"BUTTON", L"Load", WS_VISIBLE | WS_CHILD | WS_DISABLED,
		140, 60, 100, 30, hwnd, (HMENU)ID_BUTTON_LOAD, NULL, NULL);
	hButtonPlay = CreateWindow(L"BUTTON", L"Play", WS_VISIBLE | WS_CHILD | WS_DISABLED,
		260, 60, 100, 30, hwnd, (HMENU)ID_BUTTON_PLAY, NULL, NULL);
	hButtonPlayInNewWindow = CreateWindow(L"BUTTON", L"Play in New Window", WS_VISIBLE | WS_CHILD | WS_DISABLED,
		380, 60, 160, 30, hwnd, (HMENU)ID_BUTTON_PLAY_IN_NEW_WINDOW, NULL, NULL);


	hPlacementsListBox = CreateWindow(L"LISTBOX", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | LBS_STANDARD | WS_DISABLED,
		20, 110, 400, 150, hwnd, (HMENU)ID_LISTBOX_PLACEMENTS, NULL, NULL);

	//SendMessage(hPlacementsListBox, LB_ADDSTRING, 0, (LPARAM)L"List Item 1");
	//SendMessage(hPlacementsListBox, LB_ADDSTRING, 0, (LPARAM)L"List Item 2");
	//SendMessage(hPlacementsListBox, LB_ADDSTRING, 0, (LPARAM)L"List Item 3");

	hButtonShowDataInExplorer = CreateWindow(L"BUTTON", L"Show Data in Explorer", WS_VISIBLE | WS_CHILD | WS_DISABLED,
		20, 270, 200, 30, hwnd, (HMENU)ID_BUTTON_SHOW_DATA_IN_EXPLORER, NULL, NULL);
}

void CreateControlsForTab2(HWND hwnd) {
	// Initialization Options Section
	CreateWindow(L"STATIC", L"Initialization Options", WS_VISIBLE | WS_CHILD,
		20, 20, 200, 20, hwnd, NULL, NULL, NULL);

	// Incentivized Placement Alert Text Section
	CreateWindow(L"STATIC", L"Incentivized Placement Alert Text", WS_VISIBLE | WS_CHILD,
		20, 120, 300, 20, hwnd, NULL, NULL, NULL);
	hLabelIncentivizedTitle = CreateWindow(L"STATIC", L"Title:", WS_VISIBLE | WS_CHILD,
		40, 150, 60, 20, hwnd, NULL, NULL, NULL);
	hEditIncentivizedTitle = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
		120, 150, 300, 20, hwnd, (HMENU)ID_EDIT_INCENTIVIZED_TITLE, NULL, NULL);
	hLabelIncentivizedBody = CreateWindow(L"STATIC", L"Body:", WS_VISIBLE | WS_CHILD,
		40, 180, 60, 20, hwnd, NULL, NULL, NULL);
	hEditIncentivizedBody = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
		120, 180, 300, 20, hwnd, (HMENU)ID_EDIT_INCENTIVIZED_BODY, NULL, NULL);
	hLabelIncentivizedClose = CreateWindow(L"STATIC", L"Close:", WS_VISIBLE | WS_CHILD,
		40, 210, 60, 20, hwnd, NULL, NULL, NULL);
	hEditIncentivizedClose = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
		120, 210, 300, 20, hwnd, (HMENU)ID_EDIT_INCENTIVIZED_CLOSE, NULL, NULL);
	hLabelIncentivizedContinue = CreateWindow(L"STATIC", L"Continue:", WS_VISIBLE | WS_CHILD,
		40, 240, 60, 20, hwnd, NULL, NULL, NULL);
	hEditIncentivizedContinue = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP,
		120, 240, 300, 20, hwnd, (HMENU)ID_EDIT_INCENTIVIZED_CONTINUE, NULL, NULL);

	// Play Ad Options Section
	CreateWindow(L"STATIC", L"Play Ad Options", WS_VISIBLE | WS_CHILD,
		20, 280, 200, 20, hwnd, NULL, NULL, NULL);
	hLabelPositionX = CreateWindow(L"STATIC", L"X Position:", WS_VISIBLE | WS_CHILD,
		40, 310, 80, 20, hwnd, NULL, NULL, NULL);
	hEditPositionX = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER,
		130, 310, 100, 20, hwnd, (HMENU)ID_EDIT_START_XPOS, NULL, NULL);
	hLabelPositionY = CreateWindow(L"STATIC", L"Y Position:", WS_VISIBLE | WS_CHILD,
		40, 340, 80, 20, hwnd, NULL, NULL, NULL);
	hEditPositionY = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER,
		130, 340, 100, 20, hwnd, (HMENU)ID_EDIT_START_YPOS, NULL, NULL);
}

void CreateControlsForDebugTab(HWND hwnd) {
	// Network Proxy Section
	hProxyCheckbox = CreateWindow(L"BUTTON", L"Enable Network Proxy", WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX | WS_DISABLED,
		20, 20, 200, 20, hwnd, (HMENU)ID_CHECKBOX_PROXY, NULL, NULL);
	hProxyAddressLabel = CreateWindow(L"STATIC", L"Address:", WS_VISIBLE | WS_CHILD | WS_DISABLED,
		40, 50, 80, 20, hwnd, NULL, NULL, NULL);
	hProxyAddressEdit = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_DISABLED,
		130, 50, 300, 20, hwnd, (HMENU)ID_EDIT_PROXY_ADDRESS, NULL, NULL);
	hProxyPortLabel = CreateWindow(L"STATIC", L"Port:", WS_VISIBLE | WS_CHILD | WS_DISABLED,
		40, 80, 80, 20, hwnd, NULL, NULL, NULL);
	hProxyPortEdit = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | WS_DISABLED,
		130, 80, 100, 20, hwnd, (HMENU)ID_EDIT_PROXY_PORT, NULL, NULL);

	// WebView2 Debugging Section
	hWebView2DebugCheckbox = CreateWindow(L"BUTTON", L"Enable WebView2 Debugging", WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX | WS_DISABLED,
		20, 120, 200, 20, hwnd, (HMENU)ID_CHECKBOX_WEBVIEW2_DEBUG, NULL, NULL);
}

void CreatePrivacyTabControls(HWND hwnd) {
	// Remove Platform Disabled MSAID controls
	// Remove Advertiser ID controls
	// Remove ASHWID controls
	// Remove European Override checkbox

	// Disable Ashwid Tracking
	hCheckBoxDisableASHWID = CreateWindow(
		L"BUTTON", L"Disable ASHWID Tracking",
		WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_AUTO3STATE,
		20, 20, 200, 20,
		hwnd, (HMENU)ID_CHECKBOX_DISABLE_ASHWID_TRACKING, NULL, NULL);
	// Start in the unchecked state
	SendMessage(hCheckBoxDisableASHWID, BM_SETCHECK, BST_INDETERMINATE, 0);

	// CCPA Section
	CreateWindow(L"STATIC", L"CCPA Consent:", WS_VISIBLE | WS_CHILD, 20, 60, 120, 20, hwnd, NULL, NULL, NULL);
	HWND hComboCcpa = CreateWindow(L"COMBOBOX", L"", WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST, 150, 60, 120, 100, hwnd, (HMENU)ID_COMBOBOX_CCPA, NULL, NULL);
	SendMessage(hComboCcpa, CB_ADDSTRING, 0, (LPARAM)L"Opted In");
	SendMessage(hComboCcpa, CB_ADDSTRING, 0, (LPARAM)L"Opted Out");
	CreateWindow(L"BUTTON", L"Get", WS_VISIBLE | WS_CHILD, 280, 60, 60, 25, hwnd, (HMENU)ID_BUTTON_CCPA_GET, NULL, NULL);
	CreateWindow(L"BUTTON", L"Set", WS_VISIBLE | WS_CHILD, 350, 60, 60, 25, hwnd, (HMENU)ID_BUTTON_CCPA_SET, NULL, NULL);
	CreateWindow(L"STATIC", L"", WS_VISIBLE | WS_CHILD, 20, 90, 460, 20, hwnd, (HMENU)ID_LABEL_CCPA_STATUS, NULL, NULL);

	// COPPA Section
	CreateWindow(L"STATIC", L"COPPA Consent:", WS_VISIBLE | WS_CHILD, 20, 120, 120, 20, hwnd, NULL, NULL, NULL);
	HWND hComboCoppa = CreateWindow(L"COMBOBOX", L"", WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST, 150, 120, 120, 100, hwnd, (HMENU)ID_COMBOBOX_COPPA, NULL, NULL);
	SendMessage(hComboCoppa, CB_ADDSTRING, 0, (LPARAM)L"True");
	SendMessage(hComboCoppa, CB_ADDSTRING, 0, (LPARAM)L"False");
	CreateWindow(L"BUTTON", L"Get", WS_VISIBLE | WS_CHILD, 280, 120, 60, 25, hwnd, (HMENU)ID_BUTTON_COPPA_GET, NULL, NULL);
	CreateWindow(L"BUTTON", L"Set", WS_VISIBLE | WS_CHILD, 350, 120, 60, 25, hwnd, (HMENU)ID_BUTTON_COPPA_SET, NULL, NULL);
	CreateWindow(L"STATIC", L"", WS_VISIBLE | WS_CHILD, 20, 150, 460, 20, hwnd, (HMENU)ID_LABEL_COPPA_STATUS, NULL, NULL);

	// GDPR Section
	CreateWindow(L"STATIC", L"GDPR Consent:", WS_VISIBLE | WS_CHILD, 20, 180, 120, 20, hwnd, NULL, NULL, NULL);
	HWND hComboGdpr = CreateWindow(L"COMBOBOX", L"", WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST, 150, 180, 120, 100, hwnd, (HMENU)ID_COMBOBOX_GDPR, NULL, NULL);
	SendMessage(hComboGdpr, CB_ADDSTRING, 0, (LPARAM)L"Opted In");
	SendMessage(hComboGdpr, CB_ADDSTRING, 0, (LPARAM)L"Opted Out");
	//SendMessage(hComboGdpr, CB_ADDSTRING, 0, (LPARAM)L"Timed Out");
	//SendMessage(hComboGdpr, CB_ADDSTRING, 0, (LPARAM)L"Unknown");
	CreateWindow(L"STATIC", L"Consent Version:", WS_VISIBLE | WS_CHILD, 20, 210, 140, 20, hwnd, NULL, NULL, NULL);
	CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER, 150, 210, 120, 20, hwnd, (HMENU)ID_EDIT_GDPR_CONSENT_MSG_VER, NULL, NULL);
	CreateWindow(L"BUTTON", L"Get", WS_VISIBLE | WS_CHILD, 280, 180, 60, 25, hwnd, (HMENU)ID_BUTTON_GDPR_GET, NULL, NULL);
	CreateWindow(L"BUTTON", L"Set", WS_VISIBLE | WS_CHILD, 350, 180, 60, 25, hwnd, (HMENU)ID_BUTTON_GDPR_SET, NULL, NULL);
	CreateWindow(L"STATIC", L"", WS_VISIBLE | WS_CHILD, 20, 240, 460, 40, hwnd, (HMENU)ID_LABEL_GDPR_STATUS, NULL, NULL);
}

void CreateControlsForTab7(HWND hwnd) {
	RECT rcClient;
	GetClientRect(hwnd, &rcClient);
	hMultiLineEdit = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL,
		10, 10, rcClient.right - 20, rcClient.bottom - 20, hwnd, (HMENU)ID_MULTILINE_EDIT, NULL, NULL);
}

void CreateControlsForHeaderBiddingTab(HWND hwnd) {
	// Row 0: "Real Time Ads" label (bold, underlined)
	HWND hLabelRealTimeAds = CreateWindow(L"STATIC", L"Real Time Ads", WS_VISIBLE | WS_CHILD,
		20, 20, 200, 25, hwnd, (HMENU)ID_HB_LABEL_REALTIME_ADS, NULL, NULL);
	HFONT hFontBold = CreateFont(18, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
		OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"Segoe UI");
	SendMessage(hLabelRealTimeAds, WM_SETFONT, (WPARAM)hFontBold, TRUE);

	// Row 1: Get Super Token for Placement
	HWND hButtonGetSuperToken = CreateWindow(L"BUTTON", L"1.) Get Super Token (v4) for", WS_VISIBLE | WS_CHILD,
		20, 60, 200, 30, hwnd, (HMENU)ID_HB_BUTTON_GET_SUPERTOKEN, NULL, NULL);
	HWND hComboPlacements = CreateWindow(L"COMBOBOX", L"", WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST,
		230, 60, 200, 200, hwnd, (HMENU)ID_HB_COMBOBOX_PLACEMENTS, NULL, NULL);

	// Row 2: Real Time Token Example
	HWND hButtonRealTimeTokenExample = CreateWindow(L"BUTTON", L"Real Time Token Example", WS_VISIBLE | WS_CHILD,
		20, 100, 200, 30, hwnd, (HMENU)ID_HB_BUTTON_REALTIME_TOKEN_EXAMPLE, NULL, NULL);

	// Row 3: Decode/Encode Token
	HWND hButtonDecodeToken = CreateWindow(L"BUTTON", L"Decode To Json", WS_VISIBLE | WS_CHILD,
		20, 140, 150, 30, hwnd, (HMENU)ID_HB_BUTTON_DECODE_TOKEN, NULL, NULL);
	HWND hButtonEncodeToken = CreateWindow(L"BUTTON", L"Encode/Compress Json", WS_VISIBLE | WS_CHILD,
		180, 140, 170, 30, hwnd, (HMENU)ID_HB_BUTTON_ENCODE_TOKEN, NULL, NULL);

	// Row 4: IP for Adm Request
	HWND hLabelIpForAdm = CreateWindow(L"STATIC", L"IP for Adm Request:", WS_VISIBLE | WS_CHILD,
		20, 180, 150, 25, hwnd, (HMENU)ID_HB_LABEL_IP_FOR_ADM, NULL, NULL);
	HWND hEditIpForAdm = CreateWindow(L"EDIT", L"45.117.100.153", WS_VISIBLE | WS_CHILD | WS_BORDER,
		180, 180, 250, 25, hwnd, (HMENU)ID_HB_EDIT_IP_FOR_ADM, NULL, NULL);

	// Row 5: RTB Endpoints ComboBox and TextBox
	HWND hComboRtbEndpoints = CreateWindow(L"COMBOBOX", L"", WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST,
		20, 220, 150, 200, hwnd, (HMENU)ID_HB_COMBOBOX_RTB_ENDPOINTS, NULL, NULL);
	SendMessage(hComboRtbEndpoints, CB_ADDSTRING, 0, (LPARAM)L"E2E");
	SendMessage(hComboRtbEndpoints, CB_ADDSTRING, 0, (LPARAM)L"QA");
	SendMessage(hComboRtbEndpoints, CB_ADDSTRING, 0, (LPARAM)L"Newer");
	SendMessage(hComboRtbEndpoints, CB_ADDSTRING, 0, (LPARAM)L"Prod (MoPub)");
	SendMessage(hComboRtbEndpoints, CB_ADDSTRING, 0, (LPARAM)L"Prod (Max)");
	SendMessage(hComboRtbEndpoints, CB_SETCURSEL, 4, 0); // Select "Prod (Max)" by default

	HWND hEditRtbEndpoint = CreateWindow(L"EDIT", L"https://rtb.api.vungle.com/bid/t/2ffe4e7", WS_VISIBLE | WS_CHILD | WS_BORDER,
		180, 220, 400, 25, hwnd, (HMENU)ID_HB_EDIT_RTB_ENDPOINT, NULL, NULL);

	// Row 6: Get Adm From Real Time Token
	HWND hButtonGetAdm = CreateWindow(L"BUTTON", L"2.) Get Adm From Real Time Token", WS_VISIBLE | WS_CHILD,
		20, 260, 250, 30, hwnd, (HMENU)ID_HB_BUTTON_GET_ADM, NULL, NULL);

	// Row 7: Get Winning Adm
	HWND hButtonGetWinningAdm = CreateWindow(L"BUTTON", L"3.) Get Winning Adm", WS_VISIBLE | WS_CHILD,
		20, 300, 200, 30, hwnd, (HMENU)ID_HB_BUTTON_GET_WINNING_ADM, NULL, NULL);

	// Row 8: Adm Example, Decode Adm, Encode Adm
	HWND hButtonAdmExample = CreateWindow(L"BUTTON", L"Adm Example", WS_VISIBLE | WS_CHILD,
		20, 340, 120, 30, hwnd, (HMENU)ID_HB_BUTTON_ADM_EXAMPLE, NULL, NULL);
	HWND hButtonDecodeAdm = CreateWindow(L"BUTTON", L"Decode Adm", WS_VISIBLE | WS_CHILD,
		150, 340, 120, 30, hwnd, (HMENU)ID_HB_BUTTON_DECODE_ADM, NULL, NULL);
	HWND hButtonEncodeAdm = CreateWindow(L"BUTTON", L"Encode Adm", WS_VISIBLE | WS_CHILD,
		280, 340, 120, 30, hwnd, (HMENU)ID_HB_BUTTON_ENCODE_ADM, NULL, NULL);

	// Row 9: Load Ad from Adm, Play Ad from Adm, Play from Adm in New Window
	HWND hButtonLoadAdFromAdm = CreateWindow(L"BUTTON", L"4.) Load Ad from Adm", WS_VISIBLE | WS_CHILD,
		20, 380, 180, 30, hwnd, (HMENU)ID_HB_BUTTON_LOAD_AD_FROM_ADM, NULL, NULL);
	HWND hButtonPlayAdFromAdm = CreateWindow(L"BUTTON", L"5.) Play Ad from Adm", WS_VISIBLE | WS_CHILD,
		210, 380, 180, 30, hwnd, (HMENU)ID_HB_BUTTON_PLAY_AD_FROM_ADM, NULL, NULL);
	HWND hButtonPlayAdFromAdmInNewWindow = CreateWindow(L"BUTTON", L"5.) Play from Adm in New Window", WS_VISIBLE | WS_CHILD,
		400, 380, 240, 30, hwnd, (HMENU)ID_HB_BUTTON_PLAY_AD_FROM_ADM_IN_NEW_WINDOW, NULL, NULL);

	// Row 10: Real Time Ads Report TextBox
	HWND hEditRealTimeAdsReport = CreateWindow(L"EDIT", L"", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL,
		20, 420, 400, 120, hwnd, (HMENU)ID_HB_EDIT_REALTIME_ADS_REPORT, NULL, NULL);

	// Row 11: Copy/Clear Report Buttons
	HWND hButtonCopyReport = CreateWindow(L"BUTTON", L"Copy", WS_VISIBLE | WS_CHILD,
		430, 420, 80, 30, hwnd, (HMENU)ID_HB_BUTTON_COPY_REPORT, NULL, NULL);
	HWND hButtonClearReport = CreateWindow(L"BUTTON", L"Clear", WS_VISIBLE | WS_CHILD,
		430, 460, 80, 30, hwnd, (HMENU)ID_HB_BUTTON_CLEAR_REPORT, NULL, NULL);
}

void UpdatePlacementsUI(HWND hWnd)
{
	EnableWindow(hPlacementsListBox, TRUE);
	// Clear the listbox
	SendMessage(hPlacementsListBox, LB_RESETCONTENT, 0, 0);
	// Fill the listbox with placement names from g_placements
	for (const auto& placement : g_placements)
	{
		std::wstring wName = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(placement.Name);
		SendMessage(hPlacementsListBox, LB_ADDSTRING, 0, (LPARAM)wName.c_str());
	}
	// Select the first item in the listbox
	SendMessageW(hPlacementsListBox, LB_SETCURSEL, 0, 0);
	// Optionally enable the listbox and other controls
	int sel = (int)SendMessage(hPlacementsListBox, LB_GETCURSEL, 0, 0);
	EnableWindow(hButtonLoad, sel != LB_ERR);

	// Header Bidding
	// Fill hComboPlacements with placement names (just like above with hPlacementsListBox)
	// but only if the "placements" IsHeaderBidding value is set to TRUE
	HWND hComboPlacements = GetDlgItem(hTabPages[4], ID_HB_COMBOBOX_PLACEMENTS);
	if (hComboPlacements) {
		// Clear any existing items
		SendMessage(hComboPlacements, CB_RESETCONTENT, 0, 0);

		for (const auto& placement : g_placements) {
			if (placement.IsHeaderBidding) {
				std::wstring wName = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(placement.Name);
				SendMessage(hComboPlacements, CB_ADDSTRING, 0, (LPARAM)wName.c_str());
			}
		}
	}
	InvalidateRect(hWnd, NULL, TRUE); // Force a redraw
	UpdateWindow(hWnd); // Update the window to reflect changes
}

void ShowTabPage(int index) {
	for (int i = 0; i < 7; i++) {
		ShowWindow(hTabPages[i], (i == index) ? SW_SHOW : SW_HIDE);
	}
}

void ResizeTabControl(HWND hwnd) {
	RECT rcClient;
	GetClientRect(hwnd, &rcClient);

	MoveWindow(hTab, 0, 0, rcClient.right, rcClient.bottom, TRUE);

	for (int i = 0; i < 7; i++) {
		MoveWindow(hTabPages[i], 0, 25, rcClient.right, rcClient.bottom - 25, TRUE);
	}

	// Resize the multiline edit control in Tab 7
	RECT rcTab;
	GetClientRect(hTabPages[6], &rcTab);
	if (hMultiLineEdit) {
		MoveWindow(hMultiLineEdit, 10, 10, rcTab.right - 20, rcTab.bottom - 20, TRUE);
	}
}


std::wstring GetSelectedPlacementName()
{
	int sel = (int)SendMessage(hPlacementsListBox, LB_GETCURSEL, 0, 0);
	if (sel == LB_ERR) {
		return L"";
	}
	int length = (int)SendMessage(hPlacementsListBox, LB_GETTEXTLEN, sel, 0);
	std::wstring placementName(length + 1, L'\0');
	SendMessage(hPlacementsListBox, LB_GETTEXT, sel, (LPARAM)placementName.data());
	// remove trailing null if present
	if (!placementName.empty() && placementName.back() == L'\0') {
		placementName.pop_back();
	}
	return placementName;
}

// This function takes a std::wstring, replaces all instances of "\u0026" with "&",
// and standardizes multi-character line endings to a single "\r\n".
std::wstring FixAndSanitizeText(const std::wstring& input) {
	if (input.empty()) {
		return L"";
	}

	// Work on a mutable copy
	std::wstring workStr = input;

	// Replace escaped Unicode ampersand sequences such as "\u0026"
	// This looks for the "u0026" token and, if there are backslashes immediately
	// before it (e.g. "\\u0026", "\\\\u0026", etc.), removes those backslashes
	// and replaces the whole escaped sequence with a single '&'.
	const std::wstring tokenLower = L"u0026";
	size_t searchPos = 0;
	while (true) {
		// find both lower and upper 'u' occurrences
		size_t posLower = workStr.find(tokenLower, searchPos);
		size_t posUpper = workStr.find(L"U0026", searchPos);
		size_t pos;
		// pick the earliest non-npos
		if (posLower == std::wstring::npos) pos = posUpper;
		else if (posUpper == std::wstring::npos) pos = posLower;
		else pos = (posLower < posUpper ? posLower : posUpper); // avoid std::min / Win32 min macro collision

		if (pos == std::wstring::npos) break;

		// determine how many backslashes immediately precede the 'u'
		size_t start = pos;
		while (start > 0 && workStr[start - 1] == L'\\') {
			--start;
		}

		// If there is at least one backslash before the 'u', treat it as an escaped unicode sequence and replace.
		if (start < pos) {
			// replace from `start` up to pos + token length (5) with '&'
			workStr.replace(start, (pos + 5) - start, L"&");
			// continue search after the inserted '&'
			searchPos = start + 1;
		}
		else {
			// No preceding backslash, skip this occurrence (leave literal "u0026")
			searchPos = pos + 5;
		}
	}

	// Normalize line endings: collapse any sequence of \r and/or \n into a single '\n'
	std::wstring sanitizedText;
	sanitizedText.reserve(workStr.size());

	for (size_t i = 0; i < workStr.length(); ) {
		if (workStr[i] == L'\r' || workStr[i] == L'\n') {
			// skip over any contiguous CR/LF characters
			size_t j = i;
			while (j < workStr.length() && (workStr[j] == L'\r' || workStr[j] == L'\n')) {
				++j;
			}
			// append a single LF (use '\n' as canonical EOL)
			sanitizedText.push_back(L'\n');
			i = j;
		}
		else {
			sanitizedText.push_back(workStr[i]);
			++i;
		}
	}

	return sanitizedText;
}

void UpdatePlayButtonState()
{
	std::wstring placementName = GetSelectedPlacementName();
	if (!placementName.empty()) {
		// get state from m_placementLoadState
		// Convert placementName to UTF-8 for lookup
		std::string placementNameUtf8 = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(placementName);
		bool isPlayable = placementLoadState.Get(placementNameUtf8, false);
		EnableWindow(hButtonPlay, isPlayable);
		EnableWindow(hButtonPlayInNewWindow, isPlayable);
	}
}

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

