using System.Collections.Concurrent;
using NeonSprawl.Server.Game.Targeting;

namespace NeonSprawl.Server.Game.Combat;

/// <summary>Thread-safe in-memory HP for prototype combat dummies; empty at startup — lazy rows only (NEO-80).</summary>
public sealed class InMemoryCombatEntityHealthStore : ICombatEntityHealthStore
{
    private readonly ConcurrentDictionary<string, int> currentHpById = new(StringComparer.Ordinal);

    private readonly ConcurrentDictionary<string, object> idLocks = new(StringComparer.Ordinal);

    /// <inheritdoc />
    public bool TryGet(string? targetId, out CombatEntityHealthSnapshot snapshot)
    {
        var key = NormalizeTargetId(targetId);
        if (key.Length == 0 || !PrototypeTargetRegistry.TryGet(key, out _))
        {
            snapshot = default;
            return false;
        }

        lock (idLocks.GetOrAdd(key, _ => new object()))
        {
            EnsureRowInitialized(key);
            snapshot = CreateSnapshot(key, currentHpById[key]);
            return true;
        }
    }

    /// <inheritdoc />
    public bool TryApplyDamage(string? targetId, int damage, out CombatEntityHealthSnapshot snapshot)
    {
        snapshot = default;
        if (damage < 0)
        {
            return false;
        }

        var key = NormalizeTargetId(targetId);
        if (key.Length == 0 || !PrototypeTargetRegistry.TryGet(key, out _))
        {
            return false;
        }

        lock (idLocks.GetOrAdd(key, _ => new object()))
        {
            EnsureRowInitialized(key);
            var current = currentHpById[key];
            var next = Math.Max(0, current - damage);
            currentHpById[key] = next;
            snapshot = CreateSnapshot(key, next);
            return true;
        }
    }

    /// <inheritdoc />
    public bool TryResetToFull(string? targetId, out CombatEntityHealthSnapshot snapshot)
    {
        var key = NormalizeTargetId(targetId);
        if (key.Length == 0 || !PrototypeTargetRegistry.TryGet(key, out _))
        {
            snapshot = default;
            return false;
        }

        lock (idLocks.GetOrAdd(key, _ => new object()))
        {
            currentHpById[key] = PrototypeCombatConstants.MaxPrototypeTargetHp;
            snapshot = CreateSnapshot(key, PrototypeCombatConstants.MaxPrototypeTargetHp);
            return true;
        }
    }

    private void EnsureRowInitialized(string normalizedId)
    {
        if (!currentHpById.ContainsKey(normalizedId))
        {
            currentHpById[normalizedId] = PrototypeCombatConstants.MaxPrototypeTargetHp;
        }
    }

    private static CombatEntityHealthSnapshot CreateSnapshot(string targetId, int currentHp) =>
        new(
            targetId,
            PrototypeCombatConstants.MaxPrototypeTargetHp,
            currentHp,
            currentHp <= 0);

    private static string NormalizeTargetId(string? targetId) =>
        targetId?.Trim().ToLowerInvariant() ?? string.Empty;
}
