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

<root>
    <style>
        PlayerHud {
            position: absolute;
            bottom: 28px;
            left: 28px;
            width: 360px;
            pointer-events: none;
            font-family: sans-serif;
        }

        .player-hud-frame {
            flex-direction: row;
            align-items: flex-end;
            gap: 12px;
            background-color: rgba(13, 15, 20, 0.94);
            border: 1px solid rgba(229, 169, 60, 0.4);
            border-radius: 6px;
            padding: 12px 14px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.85);
        }

        .hud-left-socket .weapon-slot {
            width: 68px;
            height: 64px;
            border: 1px solid rgba(255, 255, 255, 0.15);
            border-radius: 4px;
            background-color: rgba(255, 255, 255, 0.05);
            flex-direction: column;
            justify-content: center;
            align-items: center;
            gap: 4px;
        }

        .weapon-name {
            font-size: 10px;
            font-weight: 800;
            color: #e5a93c;
            text-transform: uppercase;
            text-align: center;
        }

        .stance-indicator {
            font-size: 8px;
            font-weight: 700;
            color: #94a3b8;
            text-transform: uppercase;
        }

        .hud-gauges {
            flex-grow: 1;
            flex-direction: column;
        }

        .hud-diagnostic-warning {
            background-color: rgba(245, 158, 11, 0.9);
            color: #000000;
            font-weight: 800;
            font-size: 11px;
            padding: 8px;
            border-radius: 4px;
        }
    </style>

    @if ( ActiveFighter == null )
    {
        <div class="hud-diagnostic-warning">
            [HUD] Searching for Player Fighter...
        </div>
    }
    else
    {
        <div class="player-hud-frame">
            <div class="hud-left-socket">
                <div class="weapon-slot">
                    <span class="weapon-name">@(Combat?.CurrentWeapon?.GameObject.Name ?? "UNARMED")</span>
                    <span class="stance-indicator">@(ActiveFighter.IsParrying ? "PARRY" : "GUARD")</span>
                </div>
            </div>

            <div class="hud-gauges">
                <StatBar Label="Condition" 
                         Current="@ActiveFighter.CurrentHealth" 
                         Max="@ActiveFighter.MaxHealth" 
                         Ratio="@ActiveFighter.HealthRatio" 
                         BarType="health" />

                <StatBar Label="Balance" 
                         Current="@ActiveFighter.CurrentBalance" 
                         Max="@ActiveFighter.MaxBalance" 
                         Ratio="@ActiveFighter.BalanceRatio" 
                         BarType="balance" />

                <StatBar Label="Adrenaline" 
                         Current="@ActiveFighter.CurrentAdrenaline" 
                         Max="@ActiveFighter.MaxAdrenaline" 
                         Ratio="@ActiveFighter.AdrenalineRatio" 
                         BarType="adrenaline" />
            </div>
        </div>
    }
</root>

@code {
    [Property] public Fighter ManualFighter { get; set; }

    private Fighter _cachedFighter;
    private FighterCombat _cachedCombat;
    private TimeSince _searchThrottle = 1f;

    private Fighter ActiveFighter => ManualFighter ?? _cachedFighter;
    private FighterCombat Combat => _cachedCombat;

    protected override void OnStart()
    {
        ResolveFighter();
    }

    protected override void OnUpdate()
    {
        if ( ActiveFighter == null || !ActiveFighter.IsValid )
        {
            if ( _searchThrottle >= 0.5f )
            {
                _searchThrottle = 0f;
                ResolveFighter();
            }
        }
    }

    private void ResolveFighter()
    {
        if ( ManualFighter != null && ManualFighter.IsValid )
        {
            _cachedCombat = ManualFighter.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndDescendants )
                         ?? ManualFighter.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndAncestors );
            return;
        }

        var localFighter = Components.Get<Fighter>( FindMode.EverythingInSelfAndAncestors )
                        ?? Components.Get<Fighter>( FindMode.EverythingInSelfAndDescendants );

        if ( localFighter != null )
        {
            BindTarget( localFighter );
            return;
        }

        var playerCtrl = Scene.GetAllComponents<PlayerController>().FirstOrDefault();
        if ( playerCtrl != null )
        {
            var found = playerCtrl.Components.Get<Fighter>( FindMode.EverythingInSelfAndAncestors )
                     ?? playerCtrl.Components.Get<Fighter>( FindMode.EverythingInSelfAndDescendants );
            if ( found != null )
            {
                BindTarget( found );
                return;
            }
        }

        var humanFighter = Scene.GetAllComponents<Fighter>()
            .FirstOrDefault( f => f.Components.Get<AiBrain>( FindMode.EverythingInSelfAndAncestors ) == null );

        if ( humanFighter != null )
        {
            BindTarget( humanFighter );
        }
    }

    private void BindTarget( Fighter target )
    {
        _cachedFighter = target;
        _cachedCombat = target.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndDescendants )
                     ?? target.Components.Get<FighterCombat>( FindMode.EverythingInSelfAndAncestors );
    }

    protected override int BuildHash()
    {
        if ( ActiveFighter == null ) return 0;

        return HashCode.Combine( 
            (int)ActiveFighter.CurrentHealth, 
            (int)ActiveFighter.CurrentBalance, 
            (int)ActiveFighter.CurrentAdrenaline, 
            ActiveFighter.IsParrying,
            Combat?.CurrentWeapon?.GameObject.Id
        );
    }
}