function AuraScaling() {}

AuraScaling.prototype.Schema =
	"<optional>" +
		"<element name='BonusMultiplier' a:help='Bonus multiplier applied to aura multiply-mods per XP threshold.'>" +
			"<ref name='nonNegativeDecimal'/>" +
		"</element>" +
	"</optional>" +
	"<optional>" +
		"<element name='BonusRequiredXp' a:help='XP required to increase aura bonus by one level.'>" +
			"<data type='positiveInteger'/>" +
		"</element>" +
	"</optional>";

AuraScaling.prototype.Init = function()
{
	this.bonusMultiplier = +(this.template.BonusMultiplier || 1.0);
	this.bonusRequiredXp = +(this.template.BonusRequiredXp || 0);

	this.currentBonusLevel = 0;
	this.currentMultiplier = 1.0;
	this.currentXp = 0;

	// warn("[AuraScaling] Init entity=" + this.entity +
	// 	" BonusMultiplier=" + this.bonusMultiplier +
	// 	" BonusRequiredXp=" + this.bonusRequiredXp);

	// Promotion may not be constructed yet during component Init order.
	this.SyncFromPromotion("Init");
};

AuraScaling.prototype.GetBonusMultiplier = function()
{
	return this.currentMultiplier;
};

AuraScaling.prototype.GetCurrentBonusLevel = function()
{
	return this.currentBonusLevel;
};

/**
 * Sync XP from Promotion and recompute the aura bonus multiplier.
 * Formula: currentMultiplier = BonusMultiplier ^ floor(XP / BonusRequiredXp)
 * Example: BonusMultiplier=1.2, BonusRequiredXp=5
 *   XP 0-4  -> level 0, multiplier 1.0   (aura mods unchanged)
 *   XP 5-9  -> level 1, multiplier 1.2   (e.g. 1.3 * 1.2)
 *   XP 10-14 -> level 2, multiplier 1.44 (e.g. 1.3 * 1.2 * 1.2)
 */
AuraScaling.prototype.SyncFromPromotion = function(reason)
{
	const cmpPromotion = Engine.QueryInterface(this.entity, IID_Promotion);
	if (!cmpPromotion)
	{
		// warn("[AuraScaling] SyncFromPromotion(" + reason + ") entity=" + this.entity +
		// 	": no Promotion component yet");
		return false;
	}

	const newXp = cmpPromotion.GetCurrentXp();
	// warn("[AuraScaling] SyncFromPromotion(" + reason + ") entity=" + this.entity +
	// 	" XP=" + newXp + " (was " + this.currentXp + ")");
	this.currentXp = newXp;
	this.ComputeMultiplier();
	return true;
};

AuraScaling.prototype.ComputeMultiplier = function()
{
	if (this.bonusRequiredXp === 0)
	{
		this.currentMultiplier = 1.0;
		this.currentBonusLevel = 0;
		// warn("[AuraScaling] ComputeMultiplier entity=" + this.entity +
		// 	": BonusRequiredXp is 0, multiplier forced to 1.0");
		return;
	}

	const newBonusLevel = Math.floor(this.currentXp / this.bonusRequiredXp);
	const newMultiplier = Math.pow(this.bonusMultiplier, newBonusLevel);
	const xpIntoLevel = this.currentXp % this.bonusRequiredXp;
	const xpToNextLevel = this.bonusRequiredXp - xpIntoLevel;

	// warn("[AuraScaling] ComputeMultiplier entity=" + this.entity +
	// 	" XP=" + this.currentXp +
	// 	" level=" + newBonusLevel +
	// 	" (was " + this.currentBonusLevel + ")" +
	// 	" multiplier=" + newMultiplier +
	// 	" (was " + this.currentMultiplier + ")" +
	// 	" nextLevelIn=" + xpToNextLevel + " XP");

	if (newBonusLevel === this.currentBonusLevel && newMultiplier === this.currentMultiplier)
		return;

	// warn("[AuraScaling] Level/multiplier CHANGED entity=" + this.entity +
	// 	" " + this.currentBonusLevel + "->" + newBonusLevel +
	// 	" multiplier " + this.currentMultiplier + "->" + newMultiplier +
	// 	" (baseAuraMod * " + newMultiplier + ")");

	this.currentBonusLevel = newBonusLevel;
	this.currentMultiplier = newMultiplier;
	this.UpdateAuraBonuses();
};

/**
 * ExperienceChanged is posted as {} on this entity (see interfaces/Promotion.js).
 * Do not filter on msg.entity — the message has no such field.
 */
AuraScaling.prototype.OnExperienceChanged = function()
{
	// warn("[AuraScaling] OnExperienceChanged entity=" + this.entity);
	this.SyncFromPromotion("ExperienceChanged");
};

AuraScaling.prototype.UpdateAuraBonuses = function()
{
	// warn("[AuraScaling] UpdateAuraBonuses entity=" + this.entity +
	// 	" applying multiplier=" + this.currentMultiplier +
	// 	" level=" + this.currentBonusLevel);

	const cmpAuras = Engine.QueryInterface(this.entity, IID_Auras);
	if (cmpAuras)
		cmpAuras.ReapplyAuraModifiers();
	else
		warn("[AuraScaling] UpdateAuraBonuses entity=" + this.entity +
			": no Auras component");
};

AuraScaling.prototype.OnGlobalResearchFinished = function(msg)
{
	const cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
	if (!cmpPlayer || cmpPlayer.GetPlayerID() !== msg.player)
		return;

	const newBonusMultiplier = ApplyValueModificationsToEntity(
		"AuraScaling/BonusMultiplier", +(this.template.BonusMultiplier || 1.0), this.entity);
	const newBonusRequiredXp = ApplyValueModificationsToEntity(
		"AuraScaling/BonusRequiredXp", +(this.template.BonusRequiredXp || 0), this.entity);

	if (newBonusMultiplier === this.bonusMultiplier && newBonusRequiredXp === this.bonusRequiredXp)
		return;

	// warn("[AuraScaling] Tech modified params entity=" + this.entity +
	// 	" BonusMultiplier " + this.bonusMultiplier + "->" + newBonusMultiplier +
	// 	" BonusRequiredXp " + this.bonusRequiredXp + "->" + newBonusRequiredXp);

	this.bonusMultiplier = newBonusMultiplier;
	this.bonusRequiredXp = newBonusRequiredXp;
	this.SyncFromPromotion("ResearchFinished");
};

Engine.RegisterComponentType(IID_AuraScaling, "AuraScaling", AuraScaling);
