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

namespace IStalk.Runner
{
    public class RunnerWearableManager : NetworkBehaviour
    {
        private readonly SyncList<string> _equippedIds = new();

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

        public event Action OnWearablesChanged;

        public int SlotCount => Rules.maxWearableSlots;
        public int UsedSlots => _equippedIds.Count;
        public bool HasSpace => _equippedIds.Count < Rules.maxWearableSlots;

        public override void OnStartNetwork()
        {
            base.OnStartNetwork();
            _controller = GetComponent<RunnerController>();
            _equippedIds.OnChange += HandleWearableListChanged;
        }

        public override void OnStartClient()
        {
            base.OnStartClient();
            for (int i = 0; i < _equippedIds.Count; i++)
                ApplyWearableLocally(_equippedIds[i], true);
        }

        private void HandleWearableListChanged(SyncListOperation op, int index, string oldItem, string newItem, bool asServer)
        {
            switch (op)
            {
                case SyncListOperation.Add:
                    ApplyWearableLocally(newItem, true);
                    break;
                case SyncListOperation.RemoveAt:
                    ApplyWearableLocally(oldItem, false);
                    break;
                case SyncListOperation.Clear:
                    break;
            }
            OnWearablesChanged?.Invoke();
        }

        [ServerRpc]
        public void ServerEquipWearable(string wearableId)
        {
            if (_equippedIds.Count >= Rules.maxWearableSlots) return;
            if (_equippedIds.Contains(wearableId)) return;

            var data = ItemDatabase.Instance.GetWearable(wearableId);
            if (data == null) return;

            _equippedIds.Add(wearableId);
        }

        [ServerRpc]
        public void ServerUnequipWearable(string wearableId)
        {
            if (!_equippedIds.Contains(wearableId)) return;
            _equippedIds.Remove(wearableId);
        }

        [Server]
        public void DropAllWearables(Vector3 position)
        {
            for (int i = _equippedIds.Count - 1; i >= 0; i--)
            {
                string id = _equippedIds[i];
                _equippedIds.RemoveAt(i);
                SpawnWearableWorldItem(id, position + UnityEngine.Random.insideUnitSphere * 1.5f);
            }
        }

        [Server]
        private void SpawnWearableWorldItem(string wearableId, Vector3 position)
        {
            var data = ItemDatabase.Instance.GetWearable(wearableId);
            if (data == null || data.worldPrefab == null) return;

            var go = Instantiate(data.worldPrefab, position, Quaternion.identity);
            var nob = go.GetComponent<FishNet.Object.NetworkObject>();
            if (nob != null)
                ServerManager.Spawn(nob);
        }

        private void ApplyWearableLocally(string wearableId, bool equip)
        {
            var data = ItemDatabase.Instance.GetWearable(wearableId);
            if (data == null || _controller == null) return;

            if (equip)
                _controller.EnableAbility(data.abilityType);
            else
                _controller.DisableAbility(data.abilityType);
        }

        public string GetEquippedAt(int slot)
        {
            if (slot < 0 || slot >= _equippedIds.Count) return null;
            return _equippedIds[slot];
        }

        public bool HasWearable(string wearableId) => _equippedIds.Contains(wearableId);
    }
}
