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

namespace IStalk.Core
{
    public class ExtractionManager : NetworkBehaviour
    {
        private readonly SyncVar<int> _teamLootDeposited = new();
        private readonly SyncVar<bool> _extractionRoomUnlocked = new();
        private readonly SyncVar<bool> _allExtracted = new();

        private GlobalRules_SO Rules => GlobalRules_SO.Instance;
        private List<Vector3> _altarPositions = new();
        private ExtractionRoom _extractionRoom;
        private readonly HashSet<NetworkObject> _aliveRunners = new();

        public int TeamLootDeposited => _teamLootDeposited.Value;
        public int ExtractionThreshold => Rules.extractionThreshold;
        public bool IsExtractionMet => _teamLootDeposited.Value >= Rules.extractionThreshold;
        public bool IsRoomUnlocked => _extractionRoomUnlocked.Value;
        public int AliveRunnerCount => _aliveRunners.Count;

        public event System.Action<int> OnLootDeposited;
        public event System.Action OnExtractionThresholdMet;
        public event System.Action OnAllExtracted;

        public void SetAltarPositions(List<Vector3> positions)
        {
            _altarPositions = positions;
        }

        public void SetExtractionRoom(ExtractionRoom room)
        {
            _extractionRoom = room;
        }

        [Server]
        public void RegisterRunner(NetworkObject runner)
        {
            _aliveRunners.Add(runner);
        }

        [Server]
        public void MarkRunnerDead(NetworkObject runner)
        {
            _aliveRunners.Remove(runner);
        }

        [Server]
        public void DepositLoot(PlayerInventory inventory, int amount)
        {
            var items = inventory.GetItems();
            foreach (var id in items)
                inventory.TryRemoveItem(id);

            _teamLootDeposited.Value += amount;
            NotifyDepositObservers(_teamLootDeposited.Value);

            if (IsExtractionMet && !_extractionRoomUnlocked.Value)
            {
                _extractionRoomUnlocked.Value = true;
                if (_extractionRoom != null)
                    _extractionRoom.Unlock();
                OnExtractionThresholdMet?.Invoke();
            }
        }

        [ObserversRpc]
        private void NotifyDepositObservers(int totalDeposited)
        {
            OnLootDeposited?.Invoke(totalDeposited);
        }

        [Server]
        public void ExtractAll()
        {
            _allExtracted.Value = true;
            OnAllExtracted?.Invoke();
        }

        public bool IsNearAltar(Vector3 position)
        {
            foreach (var altar in _altarPositions)
            {
                if (Vector3.Distance(position, altar) <= Rules.altarInteractRadius)
                    return true;
            }
            return false;
        }

        public Vector3 GetNearestAltar(Vector3 position)
        {
            Vector3 nearest = Vector3.zero;
            float minDist = float.MaxValue;

            foreach (var altar in _altarPositions)
            {
                float dist = Vector3.Distance(position, altar);
                if (dist < minDist)
                {
                    minDist = dist;
                    nearest = altar;
                }
            }
            return nearest;
        }
    }
}
