#include "LiftoffInterstitialAds.h"
#include <iostream>
#include <locale>
#include <codecvt>

#include "PlacementLoadState.h"
#include "UiUtilities.h"

PlacementLoadState placementLoadState{};

/// <summary>
/// First, you must initialize the SDK with your app ID.
/// </summary>
/// <param name="hWnd"></param>
void InitializeLiftoffAds(HWND hWnd) {
	// Get appID from ID_EDIT_APP_ID control
	WCHAR appID[MAX_LOADSTRING];
	GetWindowText(hEditAppId, appID, 100);
	std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
	std::string appIDStr = converter.to_bytes(appID);

	// Call the InitializeAsync method with appID and config
	LiftoffSdkConfig config;
	// If the disable Ashwid checkbox is checked
	// Set DisableAshwidTracking based on the checkbox state
		
	int checkState = (int)SendMessage(hCheckBoxDisableASHWID, BM_GETCHECK, 0, 0);
	if (checkState == BST_CHECKED) {
		std::cout << "Disable ASHWID tracking is checked." << std::endl;
		config.SetDisableAshwidTracking(true);
	}
	else if (checkState == BST_UNCHECKED) {
		std::cout << "Disable ASHWID tracking is unchecked." << std::endl;
		config.SetDisableAshwidTracking(false); // or some default behavior
	}

	// if an item is selected in the CCPA combo box, set the CCPA value
	HWND hComboCcpa = GetDlgItem(hTabPages[3], ID_COMBOBOX_CCPA);
	int ccpaIndex = (int)SendMessage(hComboCcpa, CB_GETCURSEL, 0, 0);
	if (ccpaIndex != CB_ERR) {
		CcpaConsentStatus status = (ccpaIndex == 0) ? CcpaConsentStatus::OptedIn : CcpaConsentStatus::OptedOut;
		config.SetCcpaConsentStatus(status);
	}

	// If an item is selected in the COPPA combo box, set the COPPA value
	HWND hComboCoppa = GetDlgItem(hTabPages[3], ID_COMBOBOX_COPPA);
	int coppaIndex = (int)SendMessage(hComboCoppa, CB_GETCURSEL, 0, 0);
	if (coppaIndex != CB_ERR) {
		// 0 = True, 1 = False
		BOOL coppaStatus = (coppaIndex == 0) ? TRUE : FALSE;
		config.SetCoppaStatus(coppaStatus);
	}


	InitializationCallback initCallback;
	initCallback.OnInitializationFailure = OnLiftoffInitializationFailure;
	initCallback.OnInitializationSuccess = OnLiftoffInitializationSuccess;
	auto futureInstance2 = LiftoffAds::InitializeAsync(appIDStr, config, hWnd, initCallback);
	// Currently, this returns null -- we will fix soon...
	g_sdkInstance = futureInstance2.get();
}

/// <summary>
/// This is our callback which gets called when initialization succeeds.  We set this callback
/// above in InitializeLiftoffAds.
/// </summary>
/// <param name="args"></param>
void OnLiftoffInitializationSuccess(const InitializationSuccessEventArgs& args) {
	try
	{
		std::cout << "Initialization succeeded!" << std::endl;


		g_placements = args.Placements;

		PostMessage(hMainWnd, WM_LIFTOFF_INIT_SUCCESS, 0, 0);
	}
	catch (const std::exception& ex)
	{
		std::cout << "Error during initialization; couldn't get instance." << std::endl;
		std::cout << ex.what() << std::endl;
	}
}

/// <summary>
/// This is our callback which gets called when initialization fails.  We set this callback
/// above in InitializeLiftoffAds.
/// </summary>
/// <param name="args"></param>
void OnLiftoffInitializationFailure(const InitializationFailureEventArgs& args) {
	std::cout << "Initialization Failed!" << std::endl;
}

/// <summary>
/// This function is called when the user clicks the "Load Ad" button.
/// It allows us to set callback for load success and failure.
/// </summary>
void HandleLoadAdButton(HWND hWnd) {
	if (g_sdkInstance == nullptr) {
		MessageBox(hWnd, L"SDK instance is null!", L"Error", MB_OK | MB_ICONERROR);
		return;
	}
	std::wstring placementName = GetSelectedPlacementName();
	// Get the selected placement name
	if (!placementName.empty()) {
		while (!placementName.empty() && placementName.back() == L'\0') {
			placementName.pop_back();
		}
		// Convert to UTF-8
		std::string placementNameUtf8 = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(placementName);
		AdLoadCallback callback;
		callback.OnAdLoadFailure = OnAdLoadFailure;
		callback.OnAdLoadSuccess = OnAdLoadSuccess;

		// Load the ad using the selected placement name
		g_sdkInstance->LoadAd(
			placementNameUtf8,
			callback);
	}
}


/// <summary>
/// This callback gets called when an ad successfully loads.  We set this callback
/// in HandleLoadAdButton above.
/// </summary>
/// <param name="args"></param>
void OnAdLoadSuccess(AdLoadEventArgs args) {
	std::cout << "Ad Load Success! " << "Bundle Count: " << args.BundleCount << std::endl;
	placementLoadState.Set(args.Placement, args.AdPlayable);
	PostMessage(hMainWnd, WM_ENABLE_OR_DISABLE_PLAY_BUTTON, 0, 0);
}

/// <summary>
/// This callback gets called when an ad fails to load.  We set this callback
/// in HandleLoadAdButton above.
/// </summary>
/// <param name="args"></param>
void OnAdLoadFailure(AdLoadEventArgs args) {
	std::cout << "Ad Load Failure! " << args.ErrorMessage << std::endl;
	placementLoadState.Set(args.Placement, args.AdPlayable);
	PostMessage(hMainWnd, WM_ENABLE_OR_DISABLE_PLAY_BUTTON, 0, 0);

	// This causes a hang
	//MessageBox(hMainWnd, L"Failed to load ad.", L"LoadAd", MB_OK | MB_ICONERROR);
}

/// <summary>
/// This function is called when the user clicks the "Play Ad" button.
/// It allows us to set callbacks for ad events such as start, end, failure, rewarded, and click.
/// </summary>
/// <param name="hWnd"></param>
void HandlePlayAdButton(HWND hWnd) {
	if (g_sdkInstance == nullptr) {
		MessageBox(hWnd, L"SDK instance is null!", L"Error", MB_OK | MB_ICONERROR);
		return;
	}
	std::wstring placementName = GetSelectedPlacementName();
	// Get the selected placement name
	if (!placementName.empty()) {
		if (!placementName.empty() && placementName.back() == L'\0') {
			placementName.pop_back();
		}
		// Convert to UTF-8
		std::string placementNameUtf8 = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(placementName);
		AdPlayCallback playCallback;

		// With this line:
		playCallback.OnAdStart = OnAdStart;
		playCallback.OnAdEnd = OnAdEnd;
		playCallback.OnAdPlayFailure = OnAdPlayFailure;
		playCallback.OnAdPlayRewarded = OnAdPlayRewarded;
		playCallback.OnAdPlayClick = OnAdPlayClick;

		AdConfig config = AdConfig();
		std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
		// Set incentivized text to values in Options tab
		config.IncentivizedDialogBodyText = converter.to_bytes(GetWStringFromControl(hTabPages[1], ID_EDIT_INCENTIVIZED_BODY));
		config.IncentivizedDialogTitleText = converter.to_bytes(GetWStringFromControl(hTabPages[1], ID_EDIT_INCENTIVIZED_TITLE));
		config.IncentivizedDialogCloseButtonText = converter.to_bytes(GetWStringFromControl(hTabPages[1], ID_EDIT_INCENTIVIZED_CLOSE));
		config.IncentivizedDialogContinueButtonText = converter.to_bytes(GetWStringFromControl(hTabPages[1], ID_EDIT_INCENTIVIZED_CONTINUE));

		// Load the ad using the selected placement name
		g_sdkInstance->PlayAd(
			placementNameUtf8,
			playCallback,
			config);
		placementLoadState.Set(placementNameUtf8, g_sdkInstance->IsAdPlayable(placementNameUtf8));
		PostMessage(hWnd, WM_ENABLE_OR_DISABLE_PLAY_BUTTON, 0, 0);
	}
}

/// <summary>
/// Handles the event when the 'Play Ad in New Window' button is clicked, creating a new window 
/// and initiating ad playback using the selected placement.
/// This function is like HandlePlayAdButton above, but creates a new window for ad playback.
/// Use this method if you don't want the ad to cover your main application window, but instead
/// want it to appear in a different window.
/// </summary>
void HandlePlayAdInNewWindowButton(HWND hWnd) {
	if (g_sdkInstance == nullptr) {
		MessageBox(hWnd, L"SDK instance is null!", L"Error", MB_OK | MB_ICONERROR);
		return;
	}
	HWND hNewWindow = NULL;
	hNewWindow = CreateWindowW(
		szOtherWindowClass,        // class name of the new window
		L"Another Window",         // window title (if visible)
		WS_OVERLAPPEDWINDOW | WS_VISIBLE, // style: child + visible (must use WS_CHILD for parented windows)
		CW_USEDEFAULT, CW_USEDEFAULT,
		500, 400,                  // width, height
		hMainWnd,                  // parent window handle
		nullptr,                   // menu (or child ID if WS_CHILD)
		hInst,
		nullptr);

	std::wstring placementName = GetSelectedPlacementName();
	// Get the selected placement name
	if (!placementName.empty()) {
		if (!placementName.empty() && placementName.back() == L'\0') {
			placementName.pop_back();
		}
		// Convert to UTF-8
		std::string placementNameUtf8 = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(placementName);
		AdPlayCallback playCallback;

		// With this line:
		playCallback.OnAdStart = OnAdStart;
		playCallback.OnAdEnd = OnAdEnd;
		playCallback.OnAdPlayFailure = OnAdPlayFailure;
		playCallback.OnAdPlayRewarded = OnAdPlayRewarded;
		playCallback.OnAdPlayClick = OnAdPlayClick;
		AdConfig config = AdConfig();
		// Set the hPublisherWnd to the new window
		config.hPublisherWnd = hNewWindow;
		// Load the ad using the selected placement name
		g_sdkInstance->PlayAd(
			placementNameUtf8,
			playCallback,
			config);
		placementLoadState.Set(placementNameUtf8, g_sdkInstance->IsAdPlayable(placementNameUtf8));
		PostMessage(hWnd, WM_ENABLE_OR_DISABLE_PLAY_BUTTON, 0, 0);
	}
}

/// <summary>
/// Handles the start of an advertisement by logging its placement and event ID.
/// This callback is set in HandlePlayAdButton and HandlePlayAdInNewWindowButton above.
/// </summary>
/// <param name="args">An AdPlayEventArgs object containing information about the ad placement and event ID.</param>
void OnAdStart(AdPlayEventArgs args) {
	std::cout << "Ad started for placement: " << args.Placement << " with event id: " << args.EventID << std::endl;
}

/// <summary>
/// Handles the event triggered when an advertisement finishes playing.
/// This callback is set in HandlePlayAdButton and HandlePlayAdInNewWindowButton above.
/// </summary>
/// <param name="args">The event arguments containing information about the ad playback, including the placement.</param>
void OnAdEnd(AdPlayEventArgs args) {
	std::cout << "Ad ended for placement: " << args.Placement << std::endl;
}

/// <summary>
/// Handles the event when an advertisement fails to play.
/// This callback is set in HandlePlayAdButton and HandlePlayAdInNewWindowButton above.
/// </summary>
/// <param name="args">The event arguments containing information about the ad play failure, including the placement identifier.</param>
void OnAdPlayFailure(AdPlayEventArgs args) {
	placementLoadState.Set(args.Placement, false);
	PostMessage(hMainWnd, WM_ENABLE_OR_DISABLE_PLAY_BUTTON, 0, 0);
	std::cout << "Ad Play Failure for placement: " << args.Placement << std::endl;
}

/// <summary>
///	Handles the event when a rewarded advertisement has been successfully played.
/// A "rewarded ad" is one where the user should receive some in-app reward for watching most or all of the ad.	
/// This callback is set in HandlePlayAdButton and HandlePlayAdInNewWindowButton above.
/// </summary>
/// <param name="args"></param>
void OnAdPlayRewarded(AdPlayEventArgs args) {
	std::cout << "Ad Play Rewarded for placement: " << args.Placement << std::endl;
}

/// <summary>
///	Handles the event when an advertisement is clicked by the user.
/// </summary>
/// <param name="args"></param>
void OnAdPlayClick(AdPlayEventArgs args) {
	std::cout << "Ad Play Clicked for placement: " << args.Placement << std::endl;
}


