// Assets/_Project/Scripts/Editor/Towers/TowerIconGenerator.cs
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using TD.Towers;

namespace TD.Towers.Editor
{
    /// <summary>
    /// Editor utility that renders each <see cref="TowerDefinition"/>'s prefab to a square
    /// thumbnail PNG and assigns it back to the definition's <c>Icon</c> field, so the HUD
    /// build menu shows "how the building looks when built" on each tower tile.
    /// </summary>
    /// <remarks>
    /// Run via <b>TD &gt; Generate Tower Icons</b>. Uses <see cref="PreviewRenderUtility"/>
    /// (synchronous, controllable) rather than the async <c>AssetPreview</c> API so the whole
    /// pass completes within the menu callback. Generated PNGs are written to
    /// <c>Assets/_Project/Art/Sprites/Towers/</c>, imported as Sprites, and wired onto the
    /// matching asset. Re-running regenerates and overwrites in place.
    /// </remarks>
    public static class TowerIconGenerator
    {
        private const string OutputFolder = "Assets/_Project/Art/Sprites/Towers";
        private const int    IconSize     = 128;

        [MenuItem("TD/Generate Tower Icons")]
        public static void GenerateAll()
        {
            EnsureFolder(OutputFolder);

            string[] guids = AssetDatabase.FindAssets("t:TowerDefinition");
            if (guids.Length == 0)
            {
                Debug.LogWarning("[TowerIconGenerator] No TowerDefinition assets found.");
                return;
            }

            int generated = 0;
            try
            {
                foreach (string guid in guids)
                {
                    string defPath = AssetDatabase.GUIDToAssetPath(guid);
                    var def = AssetDatabase.LoadAssetAtPath<TowerDefinition>(defPath);
                    if (def == null || def.TowerPrefab == null)
                    {
                        Debug.LogWarning($"[TowerIconGenerator] Skipping '{defPath}' — " +
                                         "missing TowerDefinition or TowerPrefab.");
                        continue;
                    }

                    Texture2D icon = RenderPrefabIcon(def.TowerPrefab);
                    if (icon == null) continue;

                    string pngPath = $"{OutputFolder}/{def.name}.png";
                    File.WriteAllBytes(pngPath, icon.EncodeToPNG());
                    Object.DestroyImmediate(icon);

                    AssetDatabase.ImportAsset(pngPath, ImportAssetOptions.ForceSynchronousImport);
                    ConfigureAsSprite(pngPath);

                    var sprite = AssetDatabase.LoadAssetAtPath<Sprite>(pngPath);
                    AssignIcon(def, sprite);
                    generated++;
                }
            }
            finally
            {
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }

            Debug.Log($"[TowerIconGenerator] Generated {generated} tower icon(s) into {OutputFolder}.");
        }

        // ----- Rendering --------------------------------------------------

        private static Texture2D RenderPrefabIcon(GameObject prefab)
        {
            var pru = new PreviewRenderUtility();
            GameObject instance = null;
            try
            {
                instance = Object.Instantiate(prefab);
                instance.hideFlags = HideFlags.HideAndDontSave;
                pru.AddSingleGO(instance);

                if (!TryGetWorldBounds(instance, out Bounds bounds))
                {
                    Debug.LogWarning($"[TowerIconGenerator] '{prefab.name}' has no renderers to capture.");
                    return null;
                }

                // 3/4 view framed to the prefab's combined bounds.
                const float fov = 30f;
                float radius = Mathf.Max(bounds.extents.magnitude, 0.01f);
                float distance = radius / Mathf.Sin(Mathf.Deg2Rad * fov * 0.5f) * 1.15f;
                Quaternion dir = Quaternion.Euler(20f, 135f, 0f);

                var cam = pru.camera;
                cam.fieldOfView = fov;
                cam.transform.rotation = dir;
                cam.transform.position = bounds.center - dir * Vector3.forward * distance;
                cam.nearClipPlane = 0.01f;
                cam.farClipPlane = distance * 4f;
                cam.clearFlags = CameraClearFlags.SolidColor;
                cam.backgroundColor = new Color(0f, 0f, 0f, 0f); // transparent

                pru.lights[0].intensity = 1.2f;
                pru.lights[0].transform.rotation = Quaternion.Euler(40f, 40f, 0f);
                pru.lights[1].intensity = 0.6f;
                pru.ambientColor = new Color(0.35f, 0.35f, 0.35f, 1f);

                var rect = new Rect(0, 0, IconSize, IconSize);
                pru.BeginPreview(rect, GUIStyle.none);
                pru.camera.Render();
                Texture rendered = pru.EndPreview();

                var result = new Texture2D(IconSize, IconSize, TextureFormat.RGBA32, false);
                RenderTexture prev = RenderTexture.active;
                RenderTexture.active = rendered as RenderTexture;
                result.ReadPixels(rect, 0, 0);
                result.Apply();
                RenderTexture.active = prev;
                return result;
            }
            finally
            {
                if (instance != null) Object.DestroyImmediate(instance);
                pru.Cleanup();
            }
        }

        private static bool TryGetWorldBounds(GameObject go, out Bounds bounds)
        {
            var renderers = go.GetComponentsInChildren<Renderer>();
            bounds = default;
            bool any = false;
            foreach (var r in renderers)
            {
                // Skip projector/decal-style renderers that don't represent the tower body.
                if (r is MeshRenderer || r is SkinnedMeshRenderer)
                {
                    if (!any) { bounds = r.bounds; any = true; }
                    else      { bounds.Encapsulate(r.bounds); }
                }
            }
            return any;
        }

        // ----- Asset wiring -----------------------------------------------

        private static void ConfigureAsSprite(string pngPath)
        {
            var importer = AssetImporter.GetAtPath(pngPath) as TextureImporter;
            if (importer == null) return;

            importer.textureType = TextureImporterType.Sprite;
            importer.spriteImportMode = SpriteImportMode.Single;
            importer.alphaIsTransparency = true;
            importer.mipmapEnabled = false;
            importer.SaveAndReimport();
        }

        private static void AssignIcon(TowerDefinition def, Sprite sprite)
        {
            if (sprite == null) return;
            var so = new SerializedObject(def);
            so.FindProperty("Icon").objectReferenceValue = sprite;
            so.ApplyModifiedPropertiesWithoutUndo();
            EditorUtility.SetDirty(def);
        }

        private static void EnsureFolder(string assetFolder)
        {
            if (AssetDatabase.IsValidFolder(assetFolder)) return;

            string[] parts = assetFolder.Split('/');
            string current = parts[0]; // "Assets"
            for (int i = 1; i < parts.Length; i++)
            {
                string next = $"{current}/{parts[i]}";
                if (!AssetDatabase.IsValidFolder(next))
                    AssetDatabase.CreateFolder(current, parts[i]);
                current = next;
            }
        }
    }
}
