using System;

namespace GravCoin;

/// <summary>
/// Runtime state + economy math for one infrastructure machine type.
/// </summary>
public sealed class InfrastructureItem
{
	public const double PurchaseGrowth = 1.15;

	public InfrastructureItem( string id, string name, string icon, string tagline, double baseCost, double baseRevenue, float baseCycleSeconds )
	{
		Id = id;
		Name = name;
		Icon = icon;
		Tagline = tagline;
		BaseCost = Math.Max( 1.0, baseCost );
		BaseRevenue = Math.Max( 0.01, baseRevenue );
		BaseCycleSeconds = MathF.Max( 0.20f, baseCycleSeconds );
	}

	public string Id { get; }
	public string Name { get; }
	public string Icon { get; }
	public string Tagline { get; }
	public double BaseCost { get; }
	public double BaseRevenue { get; }
	public float BaseCycleSeconds { get; }

	public int Owned { get; set; }
	public bool AutomationUnlocked { get; set; }
	public bool SpeedUpgradeUnlocked { get; set; }
	public bool ProfitUpgradeUnlocked { get; set; }
	public bool IsCycleRunning { get; set; }
	public double CycleStartedAt { get; set; }
	public double LifetimeEarned { get; set; }

	public double NextPurchaseCost => CostForQuantity( 1 );
	public double AutomationCost => Math.Round( BaseCost * 12.0, 0 );
	public double SpeedUpgradeCost => Math.Round( BaseCost * 18.0, 0 );
	public double ProfitUpgradeCost => Math.Round( BaseCost * 26.0, 0 );
	public float EffectiveCycleSeconds => SpeedUpgradeUnlocked ? BaseCycleSeconds * 0.5f : BaseCycleSeconds;
	public float SafeCycleDurationSeconds => MathF.Max( 0.05f, EffectiveCycleSeconds );
	public double ProfitMultiplier => ProfitUpgradeUnlocked ? 3.0 : 1.0;
	public double RevenuePerCycle => Math.Max( 0.0, Owned * BaseRevenue * ProfitMultiplier );

	public double CostForQuantity( int quantity )
	{
		quantity = Math.Clamp( quantity, 0, 1000 );
		if ( quantity <= 0 ) return 0;

		double r = PurchaseGrowth;
		double start = BaseCost * Math.Pow( r, Owned );
		double sum = start * (Math.Pow( r, quantity ) - 1.0) / (r - 1.0);
		return Math.Round( sum, 0 );
	}

	public float ProgressPercent( double now )
	{
		if ( !IsCycleRunning ) return 0f;

		double duration = Math.Max( 0.05, EffectiveCycleSeconds );
		double elapsed = now - CycleStartedAt;

		if ( AutomationUnlocked )
		{
			// For automated machines, the bar should loop smoothly
			double progress = (elapsed % duration) / duration;
			return (float)Math.Clamp( progress * 100.0, 0.0, 100.0 );
		}

		// For manual cycles, it goes from 0 to 100 and stays at 100 (or vanishes if Manager resets it)
		return (float)Math.Clamp( elapsed / duration * 100.0, 0.0, 100.0 );
	}

	public float ProgressPercentFromElapsed( float elapsedSeconds )
	{
		if ( !IsCycleRunning ) return 0f;
		float elapsed = MathF.Max( 0f, elapsedSeconds );
		return Math.Clamp( elapsed / SafeCycleDurationSeconds * 100f, 0f, 100f );
	}

	public double ApproxAssetValue()
	{
		if ( Owned <= 0 && !AutomationUnlocked && !SpeedUpgradeUnlocked && !ProfitUpgradeUnlocked )
			return 0;

		double r = PurchaseGrowth;
		double spentUnits = Owned > 0
			? BaseCost * (Math.Pow( r, Owned ) - 1.0) / (r - 1.0)
			: 0.0;
		double spentUpgrades = 0.0;
		if ( AutomationUnlocked ) spentUpgrades += AutomationCost;
		if ( SpeedUpgradeUnlocked ) spentUpgrades += SpeedUpgradeCost;
		if ( ProfitUpgradeUnlocked ) spentUpgrades += ProfitUpgradeCost;
		return (spentUnits + spentUpgrades) * 0.80;
	}
}
