using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using BITKit;
using BITKit.Entities;
using BITKit.WorldNode;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Net.Project.B.Health
{
    [Serializable]
    public class KnockedComponent:IKnockedComponent,IWorldNode{}
    public interface IKnockedComponent
    {
        
    }
    /// <summary>
    /// 击倒服务
    /// </summary>
    public interface IKnockedService
    {
        /// <summary>
        /// 击倒列表
        /// </summary>
        public HashSet<int> Knocked { get; }
        /// <summary>
        /// 击倒生命值
        /// </summary>
        public IReadOnlyDictionary<int,int> KnockedHealth { get; }
        /// <summary>
        /// 击倒回调
        /// </summary>
        public event Action<int, bool> OnKnocked;
        /// <summary>
        /// 击倒生命值回调
        /// </summary>
        public event Action<int, int, int> OnKnockedHealthChanged;
    }

    public class KnockedService : IKnockedService,IDisposable
    {
        private readonly IEntitiesService _entitiesService;
        private readonly IHealthService _healthService;
        private readonly ILogger<KnockedService> _logger;

        public KnockedService(IHealthService healthService, ILogger<KnockedService> logger, IEntitiesService entitiesService)
        {
            _healthService = healthService;
            _logger = logger;
            _entitiesService = entitiesService;
            _healthService.OnHealthPlus += OnHealthPlus;
            _healthService.OnHealthChanged += OnHealthChanged;
        }

        private int OnHealthPlus(int id, int oldHp, int plus, object sendor)
        {
            if (_entitiesService.TryGetEntity(id, out var entity) is false) return plus;

            if (entity.ServiceProvider.GetService<IKnockedComponent>() is null) return plus;
            
            var isKnocked = _knocked.Contains(id);
            if (oldHp < 0) return plus;
            if ((oldHp + plus) > -1) return plus;
            if (plus > 0) return plus;
            if (isKnocked)
            {
                var currentHealth = _knockedHealth.GetOrAdd(id,100);
                if (currentHealth + plus > -1)
                {
                    var nextHealth = currentHealth + plus;
                    _knockedHealth[id] = nextHealth;
                    _onKnockedHealthChanged?.Invoke(id, currentHealth, nextHealth);
//                    _logger.LogInformation($"Entity {id} 的击倒生命值减少了,剩余{_knockedHealth[id]}");
                    return 0;
                }
                _knockedHealth.Set(id,-1);
                return plus;
            }
            _knockedHealth.TryAdd(id, 100);
            _knocked.Add(id);
            _onKnocked?.Invoke(id, true);
           // _logger.LogInformation($"Entity {id} 被击倒了");
            return 0;
        }

        private void OnHealthChanged(int arg1, int arg2, int arg3, object arg4)
        {
            var isKnocked = _knocked.Contains(arg1);
            if(isKnocked is false)return;
            if (arg3 <= arg2) return;
            _knocked.Remove(arg1);
            _knockedHealth.TryRemove(arg1,out _);
            _onKnocked?.Invoke(arg1, false);
            
        //    _logger.LogInformation($"Entity {arg1} 自起了");
        }

        private static readonly HashSet<int> _knocked = new();
        private static readonly ConcurrentDictionary<int,int> _knockedHealth = new();
        private static event Action<int, bool> _onKnocked;
        private static event Action<int, int, int> _onKnockedHealthChanged;
        public HashSet<int> Knocked=> _knocked;
        public IReadOnlyDictionary<int, int> KnockedHealth => _knockedHealth;
        public event Action<int, bool> OnKnocked
        {
            add => _onKnocked += value;
            remove => _onKnocked -= value;
        }
        public event Action<int, int, int> OnKnockedHealthChanged
        {
            add => _onKnockedHealthChanged += value;
            remove => _onKnockedHealthChanged -= value;
        }

        public void Dispose()
        {
            _healthService.OnHealthPlus -= OnHealthPlus;
            _healthService.OnHealthChanged -= OnHealthChanged;
        }
    }

}
