const AI_CONFIG_ROW_HEIGHT = 30;
const AI_CONFIG_ROW_MARGIN = 0;

class AIGameSettingControlDropdown extends GameSettingControlDropdown
{
	constructor(aiConfigPage, setupWindow, isSavedGame)
	{
		super(aiConfigPage, "AI", undefined, setupWindow, isSavedGame);
	}
	onOpenPage(playerIndex, enabled)
	{
		this.setEnabled(enabled);
		this.playerIndex = playerIndex;
		this.render();
	}

	/**
	 * Overloaded: no need to trigger a relayout,
	 * but updateVisibility must be called manually
	 * as the AI control manager does not subscribe to updateLayout.
	 */
	setHidden(hidden)
	{
		this.hidden = hidden;
		this.updateVisibility();
	}

	setControl(aiConfigPage)
	{
		aiConfigPage.registerOpenPageHandler(this.onOpenPage.bind(this));

		const i = aiConfigPage.getRow();

		this.frame = Engine.GetGUIObjectByName("aiSettingFrame[" + i + "]");
		this.title = this.frame.children[0];
		this.dropdown = Engine.GetGUIObjectByName("aiSettingDropdown[" + i + "]");
		this.label = this.frame.children[3];

		// For new layout: first 3 elements are in one row, rest are in 2 columns
		// No need to set position as it's handled by XML layout

		// Setup dropdown events after dropdown is initialized
		this.isInGuiUpdate = false;

		this.setHidden(false);
		this.dropdown.onSelectionChange = this.onSelectionChangeSuper.bind(this);
		if (this.onHoverChange)
			this.dropdown.onHoverChange = this.onHoverChange.bind(this);
	}
}

AIGameSettingControlDropdown.prototype.Height = AI_CONFIG_ROW_HEIGHT;

AIGameSettingControlDropdown.prototype.Margin = AI_CONFIG_ROW_MARGIN;

/**
 * Base for AI config controls that use a text input for float values (e.g. Support Ratio 0–1).
 * Uses the standard aiSettingFrame in AIConfigPage.
 */
class AIGameSettingControlFloat extends GameSettingControl
{
	constructor(aiConfigPage, setupWindow, isSavedGame)
	{
		super(aiConfigPage, "AI", undefined, setupWindow, isSavedGame);
		this.minValue = 0;
		this.maxValue = 1;
		this.defaultValue = 0.3;
		this.isInGuiUpdate = false;
	}

	setControl(aiConfigPage)
	{
		aiConfigPage.registerOpenPageHandler(this.onOpenPage.bind(this));

		const i = aiConfigPage.getRow();

		this.frame = Engine.GetGUIObjectByName("aiSettingFrame[" + i + "]");
		this.title = this.frame.children[0];
		this.input = Engine.GetGUIObjectByName("aiSettingInput[" + i + "]");
		this.label = this.frame.children[3];

		// For new layout: first 3 elements are in one row, rest are in 2 columns
		// No need to set position as it's handled by XML layout

		// Hide dropdown, show input
		const dropdown = Engine.GetGUIObjectByName("aiSettingDropdown[" + i + "]");
		if (dropdown)
		{
			dropdown.hidden = true;
			dropdown.enabled = false;
		}
		if (this.input)
		{
			this.input.hidden = false;
			this.input.enabled = true;
			this.input.onTextEdit = this.onTextEdit.bind(this);
		}

		this.setHidden(false);
	}

	onOpenPage(playerIndex, enabled)
	{
		this.playerIndex = playerIndex;
		this.render();
	}

	setHidden(hidden)
	{
		this.hidden = hidden;
		if (this.frame)
			this.frame.hidden = hidden;
	}

	setFloatValue(value)
	{
		const clampedValue = Math.max(this.minValue, Math.min(this.maxValue, value));
		if (this.input)
		{
			this.isInGuiUpdate = true;
			this.input.caption = clampedValue.toFixed(2);
			this.isInGuiUpdate = false;
		}
	}

	getFloatValue()
	{
		if (!this.input)
			return this.defaultValue;

		const text = this.input.caption;
		const value = parseFloat(text);
		return isNaN(value) ? this.defaultValue : Math.max(this.minValue, Math.min(this.maxValue, value));
	}

	onTextEdit()
	{
		if (this.isInGuiUpdate)
			return;

		const value = this.getFloatValue();
		this.onValueChange && this.onValueChange(value);
	}

	onValueChange(value)
	{
		// Override this method in subclasses
	}
}

/**
 * Base for AI config controls that use a text input for int values.
 * Uses the standard aiSettingFrame in AIConfigPage.
 */
class AIGameSettingControlInt extends GameSettingControl
{
	constructor(aiConfigPage, setupWindow, isSavedGame)
	{
		super(aiConfigPage, "AI", undefined, setupWindow, isSavedGame);
		this.minValue = 0;
		this.maxValue = 9999;
		this.defaultValue = 0;
		this.isInGuiUpdate = false;
	}

	setControl(aiConfigPage)
	{
		aiConfigPage.registerOpenPageHandler(this.onOpenPage.bind(this));

		const i = aiConfigPage.getRow();

		this.frame = Engine.GetGUIObjectByName("aiSettingFrame[" + i + "]");
		this.title = this.frame.children[0];
		this.input = Engine.GetGUIObjectByName("aiSettingInput[" + i + "]");
		this.label = this.frame.children[3];

		// For new layout: first 3 elements are in one row, rest are in 2 columns
		// No need to set position as it's handled by XML layout

		// Hide dropdown, show input
		const dropdown = Engine.GetGUIObjectByName("aiSettingDropdown[" + i + "]");
		if (dropdown)
		{
			dropdown.hidden = true;
			dropdown.enabled = false;
		}
		if (this.input)
		{
			this.input.hidden = false;
			this.input.enabled = true;
			this.input.onTextEdit = this.onTextEdit.bind(this);
		}

		this.setHidden(false);
	}

	onOpenPage(playerIndex, enabled)
	{
		this.playerIndex = playerIndex;
		this.render();
	}

	setHidden(hidden)
	{
		this.hidden = hidden;
		if (this.frame)
			this.frame.hidden = hidden;
	}

	setIntValue(value)
	{
		const clampedValue = Math.max(this.minValue, Math.min(this.maxValue, value));
		if (this.input)
		{
			this.isInGuiUpdate = true;
			this.input.caption = Math.round(clampedValue).toString();
			this.isInGuiUpdate = false;
		}
	}

	getIntValue()
	{
		if (!this.input)
			return this.defaultValue;

		const text = this.input.caption;
		const value = parseInt(text);
		return isNaN(value) ? this.defaultValue : Math.max(this.minValue, Math.min(this.maxValue, value));
	}

	onTextEdit()
	{
		if (this.isInGuiUpdate)
			return;

		const value = this.getIntValue();
		this.onValueChange && this.onValueChange(value);
	}

	onValueChange(value)
	{
		// Override this method in subclasses
	}
}
