using UnityEngine;

/// <summary>
/// MinimapObjectMarker - Creates minimap markers for cash bags and vaults.
/// Uses different shapes than character markers for differentiation.
/// CashBag = Square, Vaults = Diamond
/// 
/// IMPORTANT: You MUST create a layer called "Minimap" in Unity Project Settings
/// and configure your Main Camera to NOT render this layer.
/// </summary>
public class MinimapObjectMarker : MonoBehaviour
{
    public enum ObjectType
    {
        CashBag,
        PlayerVault,
        EnemyVault
    }
    
    [Header("Marker Settings")]
    [SerializeField] private float heightOffset = 3f;
    [SerializeField] private float markerSize = 5f;
    [SerializeField] private ObjectType objectType = ObjectType.CashBag;
    
    [Header("Colors")]
    [SerializeField] private Color cashBagColor = new Color(1f, 0.85f, 0f, 1f);      // Gold/Yellow
    [SerializeField] private Color playerVaultColor = new Color(0.2f, 0.8f, 0.2f, 1f); // Green
    [SerializeField] private Color enemyVaultColor = new Color(0.9f, 0.2f, 0.2f, 1f);  // Red
    
    [Header("Layer Settings")]
    [SerializeField] private string minimapLayerName = "Minimap";
    
    private GameObject markerObject;
    private MeshRenderer markerRenderer;
    private bool hasConfiguredLayer = false;
    private bool _markerCreated = false;
    
    private void Start()
    {
        AutoDetectType();
        
        if (!_markerCreated)
            CreateMarker();
        
        UpdateMarkerColor();
    }

    private void OnEnable()
    {
        // Re-create marker if it was destroyed (e.g. pooled object returned and re-enabled)
        if (markerObject == null)
        {
            _markerCreated = false;
            AutoDetectType();
            CreateMarker();
            UpdateMarkerColor();
        }
        else
        {
            markerObject.SetActive(true);
        }
    }

    private void OnDisable()
    {
        // Hide marker when the source object is disabled (pooled/despawned)
        if (markerObject != null)
            markerObject.SetActive(false);
    }
    
    private void AutoDetectType()
    {
        // Check if this is a CashBag
        if (GetComponent<CashBag>() != null)
        {
            objectType = ObjectType.CashBag;
            return;
        }
        
        // Check if this is a TeamVault
        TeamVault vault = GetComponent<TeamVault>();
        if (vault != null)
        {
            objectType = vault.TeamTag == "Player" ? ObjectType.PlayerVault : ObjectType.EnemyVault;
        }
    }
    
    private void LateUpdate()
    {
        if (markerObject == null) return;
        
        // Ensure layer is correctly set
        if (!hasConfiguredLayer)
        {
            ConfigureLayer();
        }
        
        // Marker is parented, so local position keeps it above owner
        // No need to update position every frame — it follows automatically
        // Only update rotation for the correct shape appearance
        if (objectType == ObjectType.CashBag)
        {
            markerObject.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
        }
        else
        {
            markerObject.transform.localRotation = Quaternion.Euler(90f, 45f, 0f);
        }
    }
    
    private void CreateMarker()
    {
        // GUARD: prevent duplicate markers
        if (_markerCreated && markerObject != null) return;
        
        // Also destroy any stale marker children from previous lifecycle
        for (int i = transform.childCount - 1; i >= 0; i--)
        {
            var child = transform.GetChild(i);
            if (child.name.Contains("MinimapObjectMarker"))
                Destroy(child.gameObject);
        }
        
        // Use different heights per type to prevent Z-fighting
        float h = heightOffset;
        switch (objectType)
        {
            case ObjectType.CashBag:     h = heightOffset;        break;
            case ObjectType.PlayerVault: h = heightOffset + 1f;   break;
            case ObjectType.EnemyVault:  h = heightOffset + 2f;   break;
        }
        
        markerObject = GameObject.CreatePrimitive(PrimitiveType.Quad);
        markerObject.name = $"{gameObject.name}_MinimapObjectMarker";
        
        // Parent to owner so it follows position automatically
        markerObject.transform.SetParent(transform, false);
        markerObject.transform.localPosition = Vector3.up * h;
        
        // Initial rotation based on type
        if (objectType == ObjectType.CashBag)
             markerObject.transform.localRotation = Quaternion.Euler(90f, 0f, 0f);
        else
             markerObject.transform.localRotation = Quaternion.Euler(90f, 45f, 0f);
             
        markerObject.transform.localScale = Vector3.one * markerSize;
        
        // Remove collider
        Collider col = markerObject.GetComponent<Collider>();
        if (col != null) Destroy(col);
        
        // Configure layer
        ConfigureLayer();
        
        // Get renderer and create material
        markerRenderer = markerObject.GetComponent<MeshRenderer>();
        
        Material markerMaterial = new Material(Shader.Find("Sprites/Default"));
        if (markerMaterial != null)
        {
            markerRenderer.material = markerMaterial;
        }
        
        _markerCreated = true;
        Debug.Log($"[MinimapObjectMarker] Created {objectType} marker for {gameObject.name}");
    }
    
    private void ConfigureLayer()
    {
        int minimapLayer = LayerMask.NameToLayer(minimapLayerName);
        
        if (minimapLayer == -1)
        {
            if (!hasConfiguredLayer)
            {
                Debug.LogError($"[MinimapObjectMarker] CRITICAL: Layer '{minimapLayerName}' not found! " +
                    "Please create this layer in Project Settings > Tags and Layers. " +
                    "Main Camera must EXCLUDE this layer from its Culling Mask!");
            }
            // Use layer 31 as fallback
            markerObject.layer = 31;
        }
        else
        {
            markerObject.layer = minimapLayer;
            hasConfiguredLayer = true;
        }
    }
    
    private void UpdateMarkerColor()
    {
        if (markerRenderer == null) return;
        
        Color targetColor;
        
        switch (objectType)
        {
            case ObjectType.CashBag:
                targetColor = cashBagColor;
                break;
            case ObjectType.PlayerVault:
                targetColor = playerVaultColor;
                break;
            case ObjectType.EnemyVault:
                targetColor = enemyVaultColor;
                break;
            default:
                targetColor = Color.white;
                break;
        }
        
        markerRenderer.material.color = targetColor;
        
        // Set texture — required for Sprites/Default in URP to render visibly
        Texture2D tex = (objectType == ObjectType.CashBag)
            ? GetSquareTexture()
            : GetDiamondTexture();
        markerRenderer.material.mainTexture = tex;
    }
    
    // ─── Texture Generation (cached statics, same pattern as MinimapMarker) ───
    
    private static Texture2D _cachedSquareTex;
    private static Texture2D _cachedDiamondTex;
    
    private static Texture2D GetSquareTexture()
    {
        if (_cachedSquareTex == null)
            _cachedSquareTex = GenerateSquareTexture();
        return _cachedSquareTex;
    }
    
    private static Texture2D GetDiamondTexture()
    {
        if (_cachedDiamondTex == null)
            _cachedDiamondTex = GenerateDiamondTexture();
        return _cachedDiamondTex;
    }
    
    private static Texture2D GenerateSquareTexture()
    {
        int size = 64;
        Texture2D tex = new Texture2D(size, size);
        Color[] colors = new Color[size * size];
        float border = 4f;
        
        for (int y = 0; y < size; y++)
        {
            for (int x = 0; x < size; x++)
            {
                bool inside = x >= border && x < size - border && y >= border && y < size - border;
                colors[y * size + x] = inside ? Color.white : Color.clear;
            }
        }
        tex.SetPixels(colors);
        tex.Apply();
        return tex;
    }
    
    private static Texture2D GenerateDiamondTexture()
    {
        int size = 64;
        Texture2D tex = new Texture2D(size, size);
        Color[] colors = new Color[size * size];
        float center = size / 2f;
        float halfSize = center - 4f;
        
        for (int y = 0; y < size; y++)
        {
            for (int x = 0; x < size; x++)
            {
                float dx = Mathf.Abs(x - center);
                float dy = Mathf.Abs(y - center);
                float dist = dx + dy; // Manhattan distance → diamond shape
                
                if (dist <= halfSize - 1.5f)
                    colors[y * size + x] = Color.white;
                else if (dist <= halfSize + 1.5f)
                {
                    float alpha = 1f - Mathf.Clamp01((dist - halfSize + 1.5f) / 3f);
                    colors[y * size + x] = new Color(1, 1, 1, alpha);
                }
                else
                    colors[y * size + x] = Color.clear;
            }
        }
        tex.SetPixels(colors);
        tex.Apply();
        return tex;
    }
    
    private void OnDestroy()
    {
        if (markerObject != null)
        {
            Destroy(markerObject);
        }
    }
    
    public void SetType(ObjectType type)
    {
        objectType = type;
        UpdateMarkerColor();
    }
    
    public void SetVisible(bool visible)
    {
        if (markerObject != null)
        {
            markerObject.SetActive(visible);
        }
    }
}
