using System.Collections.Generic;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using IStalk.Data;
using UnityEngine;

namespace IStalk.Runner
{
    public struct ActiveBuff
    {
        public string BuffId;
        public float RemainingTime;
    }

    public class RunnerBuffSystem : NetworkBehaviour
    {
        private readonly SyncList<string> _activeBuffIds = new();
        private readonly List<float> _buffTimers = new();

        private RunnerController _controller;
        private GlobalRules_SO Rules => GlobalRules_SO.Instance;

        public event System.Action OnBuffsChanged;

        public override void OnStartNetwork()
        {
            base.OnStartNetwork();
            _controller = GetComponent<RunnerController>();
            _activeBuffIds.OnChange += (op, idx, old, next, server) => OnBuffsChanged?.Invoke();
        }

        private void Update()
        {
            if (!IsServerInitialized) return;

            for (int i = _buffTimers.Count - 1; i >= 0; i--)
            {
                _buffTimers[i] -= Time.deltaTime;
                if (_buffTimers[i] <= 0)
                {
                    _activeBuffIds.RemoveAt(i);
                    _buffTimers.RemoveAt(i);
                }
            }

            ApplyProximityBuffs();
        }

        [Server]
        public void AddBuff(string buffId, float duration)
        {
            _activeBuffIds.Add(buffId);
            _buffTimers.Add(duration);
        }

        [Server]
        public void RemoveBuff(string buffId)
        {
            int idx = _activeBuffIds.IndexOf(buffId);
            if (idx >= 0)
            {
                _activeBuffIds.RemoveAt(idx);
                _buffTimers.RemoveAt(idx);
            }
        }

        private void ApplyProximityBuffs()
        {
            float linkedBonus = 0f;

            var colliders = Physics.OverlapSphere(transform.position, Rules.linkedSprintRadius);
            foreach (var col in colliders)
            {
                if (col.gameObject == gameObject) continue;
                var otherBuffs = col.GetComponentInParent<RunnerBuffSystem>();
                if (otherBuffs == null) continue;

                if (otherBuffs.HasBuff("linked_sprint"))
                    linkedBonus = Mathf.Max(linkedBonus, Rules.linkedSprintBonus);
            }

            if (HasBuff("linked_sprint"))
            {
                bool anyTeammateNearby = false;
                foreach (var col in colliders)
                {
                    if (col.gameObject == gameObject) continue;
                    if (col.GetComponentInParent<RunnerController>() != null)
                    {
                        anyTeammateNearby = true;
                        break;
                    }
                }
                if (anyTeammateNearby)
                    linkedBonus = Mathf.Max(linkedBonus, Rules.linkedSprintBonus);
            }

            if (_controller != null)
                _controller.SetSpeedBonus(linkedBonus);
        }

        public bool HasBuff(string buffId) => _activeBuffIds.Contains(buffId);

        public int ActiveBuffCount => _activeBuffIds.Count;

        public string GetBuffAt(int index)
        {
            if (index < 0 || index >= _activeBuffIds.Count) return null;
            return _activeBuffIds[index];
        }
    }
}
