using UnityEngine;

/// <summary>
/// Компонент на игроке.
/// ЛКМ — удержание → разрушение блока с прогрессом.
/// ПКМ — мгновенная постановка блока из хотбара.
/// </summary>
public class BlockPlacer : MonoBehaviour
{
    [Header("Settings")]
    public float reach        = 5f;   // дальность в Unity-единицах
    public float breakTime    = 1f;   // секунд до разрушения
    public LayerMask blockLayer;      // слой чанков (назначить в Inspector)

    [Header("Break Overlay")]
    public Material breakMaterial;    // Blocks/BlockBreak шейдер
    public Texture2D crackTexture;    // текстура трещин (grayscale)

    // ── Приватное ─────────────────────────────────────────────────────────────
    Camera       _cam;
    float        _breakProgress;
    Vector3Int   _breakingBlock = Vector3Int.one * int.MinValue; // "никакой"
    GameObject   _breakOverlay;
    MeshRenderer _overlayRenderer;

    static readonly int PropProgress = Shader.PropertyToID("_Progress");

    void Start()
    {
        _cam = Camera.main;

        if (breakMaterial == null)
        {
            var shader = Shader.Find("Blocks/BlockBreak");
            if (shader != null) breakMaterial = new Material(shader);
        }

        if (breakMaterial != null && crackTexture != null)
            breakMaterial.SetTexture("_CrackTex", crackTexture);
    }

    void Update()
    {
        HandleBreak();
        HandlePlace();
    }

    // ── Разрушение (ЛКМ удержание) ───────────────────────────────────────────

    void HandleBreak()
    {
        if (!Input.GetMouseButton(0))
        {
            CancelBreak();
            return;
        }

        if (!Raycast(out RaycastHit hit, out Vector3Int blockPos))
        {
            CancelBreak();
            return;
        }

        // Сменился ли целевой блок?
        if (blockPos != _breakingBlock)
        {
            CancelBreak();
            _breakingBlock = blockPos;
            SpawnBreakOverlay(blockPos);
        }

        _breakProgress += Time.deltaTime / breakTime;
        UpdateOverlay(_breakProgress);

        if (_breakProgress >= 1f)
        {
            FinishBreak(blockPos);
        }
    }

    void FinishBreak(Vector3Int blockPos)
    {
        string blockId = WorldManager.Instance.BreakBlock(blockPos);
        CancelBreak();

        if (blockId == null) return;

        // Дроп предмета
        var def = BlockRegistry.Instance?.GetById(blockId);
        if (def?.linkedItem != null && InventoryItemFactory.Instance != null)
        {
            Vector3 dropPos = new Vector3(blockPos.x + 0.5f, blockPos.y + 0.5f, blockPos.z + 0.5f);
            InventoryItemFactory.Instance.CreateWorldItem(def.linkedItem, 1, dropPos);
        }
    }

    void CancelBreak()
    {
        _breakProgress = 0f;
        _breakingBlock = Vector3Int.one * int.MinValue;
        if (_breakOverlay != null) Destroy(_breakOverlay);
        _breakOverlay = null;
    }

    // ── Постановка (ПКМ) ─────────────────────────────────────────────────────

    void HandlePlace()
    {
        if (!Input.GetMouseButtonDown(1)) return;
        if (!Raycast(out RaycastHit hit, out Vector3Int blockPos)) return;

        // Ячейка, куда ставим = сосед грани которую мы смотрим
        Vector3Int placePos = blockPos + Vector3Int.RoundToInt(hit.normal);

        // Не ставим блок внутри игрока
        if (IsInsidePlayer(placePos)) return;

        // Получаем блок из хотбара
        var selectedItem = InventoryManager.Instance?.GetSelectedHotbarItem();
        if (selectedItem == null) return;

        var def = BlockRegistry.Instance?.GetByItemId(selectedItem.id);
        if (def == null)
        {
            Debug.Log($"[BlockPlacer] {selectedItem.itemName} не является блоком.");
            return;
        }

        WorldManager.Instance.PlaceBlock(placePos, def.blockId);

        // Потребляем 1 из хотбара
        InventoryManager.Instance.RemoveItem(selectedItem.id, 1);
    }

    // ── Overlay разрушения ────────────────────────────────────────────────────

    void SpawnBreakOverlay(Vector3Int blockPos)
    {
        if (breakMaterial == null) return;

        _breakOverlay = GameObject.CreatePrimitive(PrimitiveType.Cube);
        _breakOverlay.name = "BreakOverlay";
        _breakOverlay.transform.position   = blockPos + new Vector3(0.5f, 0.5f, 0.5f);
        _breakOverlay.transform.localScale = Vector3.one * 1.001f; // чуть больше, без z-fight

        // Убираем коллайдер — он не нужен
        Destroy(_breakOverlay.GetComponent<Collider>());

        _overlayRenderer = _breakOverlay.GetComponent<MeshRenderer>();
        _overlayRenderer.sharedMaterial = breakMaterial;
        _overlayRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
    }

    void UpdateOverlay(float progress)
    {
        if (_overlayRenderer == null) return;
        // MaterialPropertyBlock — не создаём новый экземпляр материала
        var mpb = new MaterialPropertyBlock();
        _overlayRenderer.GetPropertyBlock(mpb);
        mpb.SetFloat(PropProgress, progress);
        _overlayRenderer.SetPropertyBlock(mpb);
    }

    // ── Утилиты ───────────────────────────────────────────────────────────────

    bool Raycast(out RaycastHit hit, out Vector3Int blockPos)
    {
        blockPos = default;
        Ray ray = new Ray(_cam.transform.position, _cam.transform.forward);

        if (Physics.Raycast(ray, out hit, reach, blockLayer))
        {
            // hit.point лежит на грани — смещаемся чуть внутрь блока
            Vector3 inner = hit.point - hit.normal * 0.01f;
            blockPos = WorldManager.WorldToBlock(inner);
            return true;
        }
        return false;
    }

    bool IsInsidePlayer(Vector3Int blockPos)
    {
        // Проверяем две ячейки (ноги и голова)
        Vector3Int feet = WorldManager.WorldToBlock(transform.position);
        Vector3Int head = WorldManager.WorldToBlock(transform.position + Vector3.up * 1.8f);
        return blockPos == feet || blockPos == head;
    }
}
