UI/HUD.razor
@using Sandbox;
@using Sandbox.UI;
@using System;
@inherits PanelComponent
@namespace Sandbox

@if(PlayerGun != null && PlayerHealth != null && HighscoreManager != null)
{
<root>
    <div class="crosshair @(PlayerGun?.IsTargetingEnemy == true ? "on-target" : "")" 
        style="transform: translate(-50%, -50%) scale(@PlayerGun.SinceShot.Relative.Remap(0f, 0.1f, 1.3f, 1f));"></div>
    <div class="hitmarker @(PlayerGun.IsHitmarkerActive ? "active" : "")"></div>
	<div class="multiplier-dial @(HighscoreManager.CalculateMultiplier() > 1.4f ? "on-fire" : "")">
        <div class="multiplier-needle" 
			style="transform: rotate( @HighscoreManager.CalculateMultiplier().Remap( 1, 2, 270, 90) deg );"></div>
	</div>
	<div class="ammocount @(Input.Pressed("attack2") ? "used" : "")">
		<p>@($"🚀{PlayerGun.CurrentRockets}")</p>
	</div>
	<div class="vitals">
	</div>
	<div class="timer">

		<div class="timer-house">	</div>
		<p>
			<span>@($"{(int)HighscoreManager.TimeSpanSinceGameStart.TotalMinutes:00}")</span>
			<span class="separator">:</span>
			<span>@($"{HighscoreManager.TimeSpanSinceGameStart.Seconds:00}")</span>
		</p>
	</div>
	<div class="score @(PlayerHealth.CurrentHealth == 0 ? $"Center" : "")">
		@foreach (var popup in activePopups)
		{
			<p class="gained-score"
				   @key="@popup.Id"
				   style="left: @(popup.RandomOffset)px;">
				@($"+{popup.Value}")
			</p>
		}
		<!-- Wir zeigen hier nun displayedScore an, gerundet auf eine Ganzzahl -->
		<p class="multiplier">@(PlayerHealth.CurrentHealth == 0 ? $"Game Over" : "")</p>
		<p class="current-score">@($"{(int)displayedScore:00000000}")</p>


	</div>
	<div class="health-dial-almost @(PlayerHealth.CurrentHealth < PlayerHealth.SetHealth * 0.2f ? "super-low-health" : PlayerHealth.CurrentHealth < PlayerHealth.SetHealth * 0.4f ? "low-health" : "")"></div>
	<div class="health-needle"
		 style="transform: rotate( @PlayerHealth.CurrentHealth.Remap(0, PlayerHealth.SetHealth, -140, 138) deg );"> </div>
</root>
}

@code
{
    public class ScorePopup
    {
        public Guid Id { get; set; } = Guid.NewGuid();
        public int Value { get; set; }
        public DateTime SpawnTime { get; set; }
        public float RandomOffset { get; set; } // Für horizontale Streuung
    }

    [Property] HighscoreManager HighscoreManager { get; set; }
    HealthSystem PlayerHealth { get; set; }
    GunControl PlayerGun { get; set; }

    private float lastHealth;
    private bool isDamaged;
    private TimeSince SinceDamage;

    private float lastRocketCount;
    private bool rocketUsed;
    private TimeSince SinceRocketUsed;

    private List<ScorePopup> activePopups = new();
    private float scoreProcessed;
    private float displayedScore = 0f; // Der Wert, der momentan angezeigt wird

    protected override void OnStart()
    {
        HighscoreManager = Scene.Get<HighscoreManager>();
        PlayerHealth = Scene.FindAllWithTag("player").First<GameObject>().GetComponent<HealthSystem>();
        PlayerGun = Scene.FindAllWithTag("player").First<GameObject>().GetComponent<GunControl>();

        lastHealth = PlayerHealth.CurrentHealth;
        // Initialisierung, damit der Score nicht bei 0 startet, wenn man einsteigt
        displayedScore = HighscoreManager.CurrentScore;
    }

    protected override void OnUpdate()
    {
        // Wir nähern displayedScore dem echten Score an.
        // 5f ist die Geschwindigkeit. Höhere Werte = schnelleres Hochzählen.
        displayedScore = MathX.Lerp(displayedScore, HighscoreManager.CurrentScore, Time.Delta * 5f);

        // Kleiner Fix: Wenn die Differenz winzig ist, hart setzen, um Flackern zu vermeiden
        if (Math.Abs(displayedScore - HighscoreManager.CurrentScore) < 0.5f)
        {
            displayedScore = HighscoreManager.CurrentScore;
        }

        // 2. Neue Punkte erkennen und Popup hinzufügen
        if (HighscoreManager.CurrentScore > scoreProcessed)
        {
            int diff = (int)(HighscoreManager.CurrentScore - scoreProcessed);
            if (diff > 0)
            {
                activePopups.Add(new ScorePopup
				{
					Value = (int)diff,
					SpawnTime = DateTime.Now,
                    // Ein zufälliger Versatz, damit die Zahlen nicht alle exakt übereinander liegen
					RandomOffset = Random.Shared.Float(150, 155)
				});
            }

            scoreProcessed = HighscoreManager.CurrentScore;
        }

        // 3. Alte Popups entfernen (nach 0.6 Sekunden, passend zur CSS Animation)
        activePopups.RemoveAll(p => (DateTime.Now - p.SpawnTime).TotalSeconds > 1);

        // Schadens-Check
        if (PlayerHealth.CurrentHealth < lastHealth)
        {
            // Schaden wurde erkannt!
            isDamaged = true;
            SinceDamage = 0; // Dauer der Animation in Sekunden
        }

        lastHealth = PlayerHealth.CurrentHealth;

        // Timer herunterzählen, um die Klasse wieder zu entfernen
        if (SinceDamage > 0.2f)
        {
            isDamaged = false;
        }

        // Rocket-Check
        if (PlayerGun.CurrentRockets != lastRocketCount)
        {
            rocketUsed = true;
            SinceRocketUsed = 0; // Dauer der Animation in Sekunden
        }
        if (SinceRocketUsed > 0.5f)
        {
            rocketUsed = false;
        }
    }

    protected override int BuildHash() {

        if (HighscoreManager == null || PlayerHealth == null || PlayerGun == null)
        {
            return 0;
        }

        var hash = new System.HashCode();
        hash.Add(displayedScore);
        hash.Add(HighscoreManager.LastGainedScore);
        hash.Add(HighscoreManager.TimeSpanSinceGameStart.Seconds);
        hash.Add(activePopups.Count);
        hash.Add(HighscoreManager.CalculateMultiplier());
        hash.Add(PlayerHealth.CurrentHealth);
        hash.Add(isDamaged);
        hash.Add(PlayerGun.CurrentRockets);
        hash.Add(PlayerGun.IsTargetingEnemy);
        hash.Add(PlayerGun.IsHitmarkerActive);
        hash.Add(PlayerGun.SinceShot.Relative);

        return hash.ToHashCode(); 
    }
}