/**
 * This is the main menu screen of the campaign.
 * It shows you the currently available scenarios, scenarios you've already completed, etc.
 * This particular variant is extremely simple and shows a list similar to Age 1's campaigns,
 * but conceptually nothing really prevents more complex systems.
 */
class CampaignMenu extends AutoWatcher
{
	constructor(campaignRun)
	{
		super("render");

		this.run = campaignRun;

		this.selectedLevel = -1;
		this.levelSelection = Engine.GetGUIObjectByName("levelSelection");
		this.levelSelection.onSelectionChange = () => { this.selectedLevel = this.levelSelection.selected; };

		this.levelSelection.onMouseLeftDoubleClickItem = () => this.startScenario();
		Engine.GetGUIObjectByName('startButton').onPress = () => this.startScenario();
		Engine.GetGUIObjectByName('backToMain').onPress = () => this.goBackToMainMenu();
		Engine.GetGUIObjectByName('savedGamesButton').onPress = this.loadSavegame.bind(this);

		this.mapCache = new MapCache();

		this._ready = true;
	}

	async loadSavegame()
	{
		const gameId = await Engine.OpenChildPage(
			'page_loadgame.xml',
			{
				"campaignRun": this.run.filename
			});

		if (!gameId)
			return;

		const metadata = Engine.StartSavedGame(gameId);
		if (!metadata)
		{
			error("Could not load saved game: " + gameId);
			return;
		}

		Engine.SwitchGuiPage("page_loading.xml", {
			"attribs": metadata.initAttributes,
			"playerAssignments": {
				"local": {
					"name":
						metadata.initAttributes.settings.PlayerData[metadata.playerID]?.Name ??
						singleplayerName(),
					"player": metadata.playerID
				}
			},
			"savedGUIData": metadata.gui
		});
	}

	goBackToMainMenu()
	{
		this.run.save();
		Engine.SwitchGuiPage("page_pregame.xml", {});
	}

	startScenario()
	{
		const level = this.getSelectedLevelData();
		if (!meetsRequirements(this.run, level))
			return;

		// TODO: level description should also be passed, ideally.
		const settings = {
			"mapType": level.MapType,
			"map": "maps/" + level.Map,
			"settings": {
				// TODO: don't translate this here.
				"mapName": this.getLevelName(level),
				"mapPreview": level.Preview && "cropped:" + 400/512 + "," + 300/512 + ":" + level.Preview,
				"CheatsEnabled": true
			},
			"campaignData": {
				"run": this.run.filename,
				"levelID": this.levelSelection.list_data[this.selectedLevel],
				"data": this.run.data
			}
		};
		const assignments = {
			"local": {
				"player": 1,
				"name": Engine.ConfigDB_GetValue("user", "playername.singleplayer") || Engine.GetSystemUsername()
			}
		};

		const gameSettings = new GameSettings().init();
		gameSettings.fromInitAttributes(settings);

		if (level.useGameSetup)
		{
			// Setup some default AI on the non-human players.
			for (let i = 1; i < gameSettings.playerCount.nbPlayers; ++i)
				gameSettings.playerAI.set(i, {
					"bot": g_Settings.PlayerDefaults[i + 1].AI,
					"difficulty": +Engine.ConfigDB_GetValue("user", "gui.gamesetup.aidifficulty"),
					"behavior": Engine.ConfigDB_GetValue("user", "gui.gamesetup.aibehavior"),
				});

			const attributes = gameSettings.toInitAttributes();
			attributes.guiData = {
				"lockSettings": {
					"map": true,
				},
			};

			Engine.SwitchGuiPage("page_gamesetup.xml", {
				"backPage": {
					"page": this.run.getMenuPath(),
					"data": {
						"filename": this.run.filename
					}
				},
				"gameSettings": attributes,
			});
			return;
		}

		gameSettings.launchGame(assignments, true);
		Engine.SwitchGuiPage("page_loading.xml", {
			"attribs": gameSettings.finalizedAttributes,
			"playerAssignments": assignments
		});
	}

	getSelectedLevelData()
	{
		if (this.selectedLevel === -1)
			return undefined;
		return this.run.template.Levels[this.levelSelection.list_data[this.selectedLevel]];
	}

	shouldShowLevel(levelData)
	{
		if (this.run.template.ShowUnavailable)
			return true;

		return meetsRequirements(this.run, levelData);
	}

	getLevelName(levelData)
	{
		if (levelData.Name)
			return translateWithContext("Campaign Template", levelData.Name);
		return translate(this.mapCache.getTranslatableMapName(levelData.MapType, "maps/" + levelData.Map));
	}

	getLevelDescription(levelData)
	{
		if (levelData.Description)
			return translateWithContext("Campaign Template", levelData.Description);
		return this.mapCache.getTranslatedMapDescription(levelData.MapType, "maps/" + levelData.Map);

	}

	getLevelPreview(levelData)
	{
		if (levelData.Preview)
			return "cropped:" + 400/512 + "," + 300/512 + ":" + levelData.Preview;
		return this.mapCache.getMapPreview(levelData.MapType, "maps/" + levelData.Map);
	}

	displayLevelsList()
	{
		let list = [];
		for (const key in this.run.template.Levels)
		{
			const level = this.run.template.Levels[key];

			if (!this.shouldShowLevel(level))
				continue;

			let status = "";
			let name = this.getLevelName(level);
			if (isCompleted(this.run, key))
				status = translateWithContext("campaign status", "Completed");
			else if (meetsRequirements(this.run, level))
				status = coloredText(translateWithContext("campaign status", "Available"), "green");
			else
				name = coloredText(name, "gray");

			list.push({ "ID": key, "name": name, "status": status });
		}

		list.sort((a, b) => this.run.template.Order.indexOf(a.ID) - this.run.template.Order.indexOf(b.ID));

		list = prepareForDropdown(list);

		this.levelSelection.list_name = list.name || [];
		this.levelSelection.list_status = list.status || [];

		// COList needs these changed last or crashes.
		this.levelSelection.list = list.ID || [];
		this.levelSelection.list_data = list.ID || [];
	}

	displayLevelDetails()
	{
		if (this.selectedLevel === -1)
		{
			Engine.GetGUIObjectByName("startButton").enabled = false;
			Engine.GetGUIObjectByName("startButton").hidden = false;
			return;
		}

		const level = this.getSelectedLevelData();

		Engine.GetGUIObjectByName("scenarioName").caption = this.getLevelName(level);
		Engine.GetGUIObjectByName("scenarioDesc").caption = this.getLevelDescription(level);
		Engine.GetGUIObjectByName('levelPreviewBox').sprite = this.getLevelPreview(level);

		Engine.GetGUIObjectByName("startButton").enabled = meetsRequirements(this.run, level);
		Engine.GetGUIObjectByName("startButton").hidden = false;
		Engine.GetGUIObjectByName("loadSavedButton").hidden = true;
	}

	render()
	{
		Engine.GetGUIObjectByName("campaignTitle").caption = this.run.getLabel();
		this.displayLevelDetails();
		this.displayLevelsList();
	}
}


var g_CampaignMenu;

function init(initData)
{
	let run = initData?.filename || CampaignRun.getCurrentRunFilename();
	try {
		run = new CampaignRun(run).load();
		if (!run.isCurrent())
			run.setCurrent();
		g_CampaignMenu = new CampaignMenu(run);
	} catch (err) {
		error(sprintf("Error loading campaign run %s: %s.", CampaignRun.getCurrentRunFilename(), err));
		Engine.SwitchGuiPage("page_pregame.xml", {});
	}
}
