using UnityEngine;

namespace eagle {
    /// <summary>
    /// Clips a 3D model to the map viewport by toggling renderer visibility each frame.
    /// Used for beast/animal/dragon/monster models to avoid shader replacement, which
    /// can break models with vertex colors.  Reads the global _ViewportClipRect and
    /// _PopupClipRect properties already broadcast by ViewportClipper and PopupClipper.
    /// </summary>
    public class RendererViewportClipper : MonoBehaviour {
        private static readonly int ViewportClipRectId = Shader.PropertyToID("_ViewportClipRect");
        private static readonly int PopupClipRectId = Shader.PropertyToID("_PopupClipRect");

        private Renderer[] _renderers;

        public static void Attach(GameObject target) {
            if (!target.TryGetComponent<RendererViewportClipper>(out _)) {
                target.AddComponent<RendererViewportClipper>();
            }
        }

        // Transparent queue (3000) + 100, matching the old ClipRectMeshUnlit shader so
        // beast models render above the province color texture.
        private const int RenderQueue = 3100;

        void Awake() {
            _renderers = GetComponentsInChildren<Renderer>();
            foreach (var r in _renderers) {
                foreach (var mat in r.materials) { mat.renderQueue = RenderQueue; }
            }
        }

        void LateUpdate() {
            if (_renderers == null || _renderers.Length == 0) return;

            var viewport = Shader.GetGlobalVector(ViewportClipRectId);
            var popup = Shader.GetGlobalVector(PopupClipRectId);

            foreach (var r in _renderers) {
                var screenPos = RendererScreenCenter(r);
                bool insideViewport = viewport.z > 0 && screenPos.x >= viewport.x &&
                                      screenPos.x <= viewport.z && screenPos.y >= viewport.y &&
                                      screenPos.y <= viewport.w;
                bool insidePopup = popup.z > 0 && screenPos.x >= popup.x &&
                                   screenPos.x <= popup.z && screenPos.y >= popup.y &&
                                   screenPos.y <= popup.w;
                r.enabled = insideViewport && !insidePopup;
            }
        }

        private static Vector2 RendererScreenCenter(Renderer r) {
            var worldCenter = r.bounds.center;
            var canvas = r.GetComponentInParent<Canvas>();
            if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay) {
                return new Vector2(worldCenter.x, worldCenter.y);
            }
            var cam = canvas != null ? canvas.worldCamera : Camera.main;
            if (cam != null) { return cam.WorldToScreenPoint(worldCenter); }
            return new Vector2(worldCenter.x, worldCenter.y);
        }
    }
}
