using FishNet.Object;
using UnityEngine;
using IStalk.Core;
using IStalk.Data;
using IStalk.Shared;
using IStalk.UI;

namespace IStalk.Runner
{
    public class RunnerInteraction : NetworkBehaviour
    {
        [SerializeField] private float _interactRange = 2f;
        [SerializeField] private LayerMask _interactLayer;

        private PlayerInventory _inventory;
        private WeightComponent _weight;
        private ShrineItemEffect _shrineEffect;
        private RunnerHealth _health;
        private RunnerHUD _hud;
        private ShrineUI _shrineUI;
        private DamageIndicator _damageIndicator;
        private ExtractionManager _extraction;
        private float _channelProgress;
        private WorldItem _nearestItem;
        private Shrine _nearestShrine;

        public float ChannelProgress => _channelProgress;

        public override void OnStartClient()
        {
            base.OnStartClient();
            if (!IsOwner)
            {
                enabled = false;
                return;
            }

            _inventory = GetComponent<PlayerInventory>();
            _weight = GetComponent<WeightComponent>();
            _shrineEffect = GetComponent<ShrineItemEffect>();
            _health = GetComponent<RunnerHealth>();
            _hud = FindAnyObjectByType<RunnerHUD>();
            _shrineUI = FindAnyObjectByType<ShrineUI>();
            _damageIndicator = FindAnyObjectByType<DamageIndicator>();
            _extraction = FindAnyObjectByType<ExtractionManager>();

            if (_hud != null)
                _hud.Initialize(_inventory, _weight);
            if (_damageIndicator != null && _health != null)
                _damageIndicator.Initialize(_health);
        }

        private void Update()
        {
            if (!IsOwner) return;
            if (_health != null && _health.IsDown) return;
            if (_shrineUI != null && _shrineUI.IsOpen) return;

            ScanForInteractables();
            HandleInput();
        }

        private void ScanForInteractables()
        {
            _nearestItem = null;
            _nearestShrine = null;

            Collider[] hits = Physics.OverlapSphere(transform.position, _interactRange, _interactLayer);

            float minItemDist = float.MaxValue;
            foreach (var hit in hits)
            {
                var item = hit.GetComponent<WorldItem>();
                if (item != null)
                {
                    float dist = Vector3.Distance(transform.position, item.transform.position);
                    if (dist < minItemDist)
                    {
                        minItemDist = dist;
                        _nearestItem = item;
                    }
                }

                var shrine = hit.GetComponent<Shrine>();
                if (shrine != null && shrine.IsPlayerInRange(transform.position))
                    _nearestShrine = shrine;
            }

            UpdatePrompt();
        }

        private void UpdatePrompt()
        {
            if (_hud == null) return;

            if (_nearestItem != null)
            {
                var data = ItemDatabase.Instance.GetLootItem(_nearestItem.ItemId);
                string name = data != null ? data.displayName : "Item";
                float weight = data != null ? data.weight : 0;
                _hud.ShowInteractPrompt($"[F] Pick up {name} ({weight:F1}kg)");
            }
            else if (_nearestShrine != null)
            {
                _hud.ShowInteractPrompt("[F] Open Shrine");
            }
            else if (_extraction != null && _extraction.IsNearAltar(transform.position))
            {
                if (_extraction.IsExtractionMet)
                    _hud.ShowInteractPrompt("[Hold F] Extract");
                else
                    _hud.ShowInteractPrompt($"[Hold F] Deposit ({_inventory.TotalLootValue} value)");
            }
            else
            {
                _hud.HideInteractPrompt();
            }
        }

        private void HandleInput()
        {
            if (Input.GetKeyDown(KeyCode.Q) && _shrineEffect != null && _shrineEffect.HasActiveItem)
            {
                ServerUseItem();
            }

            if (Input.GetKeyDown(KeyCode.F))
            {
                if (_nearestItem != null)
                {
                    ServerPickupItem(_nearestItem);
                    return;
                }
                if (_nearestShrine != null && _shrineUI != null)
                {
                    _shrineUI.Show(_nearestShrine, _inventory);
                    return;
                }
            }

            if (Input.GetKey(KeyCode.F) && _extraction != null && _extraction.IsNearAltar(transform.position))
            {
                float channelTime = GlobalRules_SO.Instance.GetChannelTime(_weight.CurrentWeight);
                _channelProgress += Time.deltaTime / channelTime;

                if (_channelProgress >= 1f)
                {
                    _channelProgress = 0;
                    ServerDeposit();
                }
            }
            else
            {
                _channelProgress = 0;
            }

            if (Input.GetKeyDown(KeyCode.G) && _inventory.UsedSlots > 0)
            {
                ServerDropItem();
            }
        }

        [ServerRpc]
        private void ServerPickupItem(WorldItem item)
        {
            if (item == null) return;
            float dist = Vector3.Distance(transform.position, item.transform.position);
            if (dist > GlobalRules_SO.Instance.pickupRadius * 1.5f) return;
            item.PickUp(_inventory);
        }

        [ServerRpc]
        private void ServerDeposit()
        {
            int value = _inventory.TotalLootValue;
            if (value <= 0) return;
            _extraction.DepositLoot(_inventory, value);
        }

        [ServerRpc]
        private void ServerUseItem()
        {
            if (_shrineEffect != null)
                _shrineEffect.ActivateItem();
        }

        [ServerRpc]
        private void ServerDropItem()
        {
            var items = _inventory.GetItems();
            if (items.Count == 0) return;
            string lastItem = items[^1];
            _inventory.TryRemoveItem(lastItem);
            WorldItem.SpawnWorldItem(lastItem, transform.position + transform.forward);
        }
    }
}
