using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

/// <summary>
/// Обработка Drag & Drop предметов между слотами и выброс за пределы инвентаря
/// </summary>
public class InventoryDragDrop : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler, IPointerEnterHandler, IPointerExitHandler
{
    public Slot slot;
    public int slotIndex;

    [Header("Drag Visual")]
    [SerializeField] private RectTransform dragIcon;
    [SerializeField] private Image dragImage;
    [SerializeField] private float dragIconScale = 1.2f;

    [Header("Drop Settings")]
    [SerializeField] private bool allowDropOutside = true;
    [SerializeField] private float dropThreshold = 100f; // пикселей за пределами инвентаря

    private Canvas _canvas;
    private CanvasGroup _canvasGroup;
    private bool _isDragging;
    private Vector2 _dragStartPosition;
    private RectTransform _inventoryPanelRect;

    void Start()
    {
        _canvas = GetComponentInParent<Canvas>();
        _canvasGroup = GetComponent<CanvasGroup>();

        if (dragIcon == null)
        {
            CreateDragIcon();
        }

        // Находим панель инвентаря
        var inventoryManager = FindObjectOfType<InventoryManager>();
        if (inventoryManager?.inventoryPanel != null)
        {
            _inventoryPanelRect = inventoryManager.inventoryPanel.GetComponent<RectTransform>();
        }

        if (dragIcon != null)
            dragIcon.gameObject.SetActive(false);
    }

    private void CreateDragIcon()
    {
        GameObject canvasGO = new GameObject("DragIconCanvas");
        canvasGO.transform.SetParent(_canvas != null ? _canvas.transform : transform.root);

        var dragCanvas = canvasGO.AddComponent<Canvas>();
        dragCanvas.overrideSorting = true;
        dragCanvas.sortingOrder = 1000;
        dragCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
        canvasGO.AddComponent<GraphicRaycaster>();

        dragIcon = new GameObject("DragIcon").AddComponent<RectTransform>();
        dragIcon.SetParent(canvasGO.transform, false);
        dragIcon.sizeDelta = new Vector2(48, 48);

        dragImage = dragIcon.gameObject.AddComponent<Image>();
        dragImage.raycastTarget = false;

        dragIcon.gameObject.SetActive(false);
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (slot == null || slot.IsEmpty) return;

        _isDragging = true;
        _dragStartPosition = eventData.position;

        if (_canvasGroup != null)
            _canvasGroup.blocksRaycasts = false;

        if (dragIcon != null && slot.item?.icon != null)
        {
            dragIcon.gameObject.SetActive(true);
            dragImage.sprite = slot.item.icon;
            dragIcon.localScale = Vector3.one * dragIconScale;
            dragIcon.position = eventData.position;
        }

        var bg = GetComponent<Image>();
        if (bg != null)
            bg.color = new Color(1f, 1f, 1f, 0.5f);
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (!_isDragging || dragIcon == null) return;
        dragIcon.position = eventData.position;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (!_isDragging) return;

        _isDragging = false;

        if (dragIcon != null)
        {
            dragIcon.gameObject.SetActive(false);
            dragIcon.localScale = Vector3.one;
        }

        if (_canvasGroup != null)
            _canvasGroup.blocksRaycasts = true;

        var bg = GetComponent<Image>();
        if (bg != null)
            bg.color = slot.IsEmpty ? new Color(0.25f, 0.25f, 0.25f, 0.8f) : new Color(0.35f, 0.35f, 0.35f, 0.95f);

        // Проверяем - выбросили за пределы инвентаря?
        if (allowDropOutside && IsOutsideInventory(eventData.position))
        {
            DropItemOutside();
            return;
        }

        // Иначе - пробуем переместить в другой слот
        var raycastResults = new System.Collections.Generic.List<RaycastResult>();
        EventSystem.current.RaycastAll(eventData, raycastResults);

        Slot targetSlot = null;

        foreach (var result in raycastResults)
        {
            var slotComponent = result.gameObject.GetComponent<Slot>();
            if (slotComponent != null && slotComponent != slot)
            {
                targetSlot = slotComponent;
                break;
            }
        }

        if (targetSlot != null && InventoryManager.Instance != null)
        {
            InventoryManager.Instance.SwapSlots(slotIndex, targetSlot.slotIndex);
        }
    }

    private bool IsOutsideInventory(Vector2 screenPosition)
    {
        if (_inventoryPanelRect == null) return false;

        // Получаем границы панели инвентаря в экранных координатах
        Vector3[] corners = new Vector3[4];
        _inventoryPanelRect.GetWorldCorners(corners);

        // rect панели в экранных координатах
        float minX = corners[0].x;
        float maxX = corners[2].x;
        float minY = corners[0].y;
        float maxY = corners[2].y;

        // Добавляем отступ
        float threshold = dropThreshold;

        // Проверяем находится ли курсор за пределами панели + threshold
        bool outside = screenPosition.x < minX - threshold ||
                       screenPosition.x > maxX + threshold ||
                       screenPosition.y < minY - threshold ||
                       screenPosition.y > maxY + threshold;

        return outside;
    }

    private void DropItemOutside()
    {
        if (slot == null || slot.IsEmpty) return;

        var item = slot.item;
        int amount = slot.amount;

        // Определяем позицию выброса
        Vector3 dropPos = Vector3.zero;
        if (Camera.main != null)
        {
            // Выбрасываем перед игроком
            dropPos = Camera.main.transform.position + Camera.main.transform.forward * 2f;
        }

        // Создаём предмет в мире
        if (InventoryItemFactory.Instance != null)
        {
            InventoryItemFactory.Instance.DropItem(item, amount, dropPos);
        }
        else
        {
            // Fallback - просто создаём объект
            var go = new GameObject($"Dropped_{item.itemName}");
            go.transform.position = dropPos;

            var visual = GameObject.CreatePrimitive(PrimitiveType.Cube);
            visual.transform.SetParent(go.transform);
            visual.transform.localPosition = Vector3.zero;
            visual.transform.localScale = Vector3.one * 0.3f;
            DestroyImmediate(visual.GetComponent<Collider>());

            var worldItem = go.AddComponent<WorldItem>();
            worldItem.Setup(item, amount);
        }

        // Очищаем слот
        slot.Clear();

        Debug.Log($"[DragDrop] Выброшен: {item.itemName} x{amount}");
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        if (!_isDragging && slot != null && !slot.IsEmpty)
        {
            var bg = GetComponent<Image>();
            if (bg != null)
                bg.color = new Color(0.5f, 0.5f, 0.5f, 1f);
        }
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        if (!_isDragging && slot != null)
        {
            var bg = GetComponent<Image>();
            if (bg != null)
                bg.color = slot.IsEmpty ?
                    new Color(0.25f, 0.25f, 0.25f, 0.8f) :
                    new Color(0.35f, 0.35f, 0.35f, 0.95f);
        }
    }
}