using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace InfiniteWorld.Editor
{
    public class WorldGeneratorEditorWindow : EditorWindow
    {
        private static readonly AutoTileShape[] WallShapeOrder =
        {
            AutoTileShape.OuterTopLeft,
            AutoTileShape.Top,
            AutoTileShape.OuterTopRight,
            AutoTileShape.Left,
            AutoTileShape.Center,
            AutoTileShape.Right,
            AutoTileShape.OuterBottomLeft,
            AutoTileShape.Bottom,
            AutoTileShape.OuterBottomRight,
            AutoTileShape.InnerTopLeft,
            AutoTileShape.InnerTopRight,
            AutoTileShape.InnerBottomLeft,
            AutoTileShape.InnerBottomRight
        };

        private WorldAutotileProfile profile;
        private SerializedObject serializedProfile;
        private Vector2 scroll;

        [MenuItem("Tools/Infinite World/World Builder")]
        public static void Open()
        {
            GetWindow<WorldGeneratorEditorWindow>("World Builder");
        }

        private void OnGUI()
        {
            DrawToolbar();
            EditorGUILayout.Space(6f);

            if (profile == null)
            {
                EditorGUILayout.HelpBox("Assign or create a WorldAutotileProfile. The workflow is: create the authoring layout prefab, edit tiles inside that grid, then build the final profile back from the layout.", MessageType.Info);
                return;
            }

            if (serializedProfile == null || serializedProfile.targetObject != profile)
            {
                serializedProfile = new SerializedObject(profile);
            }

            serializedProfile.Update();
            scroll = EditorGUILayout.BeginScrollView(scroll);

            DrawPaletteTools();
            EditorGUILayout.Space(8f);
            DrawValidation();
            EditorGUILayout.Space(8f);
            DrawProfileFields();

            EditorGUILayout.EndScrollView();
            serializedProfile.ApplyModifiedProperties();

            if (GUI.changed)
            {
                EditorUtility.SetDirty(profile);
                WorldAutotileProfilePipeline.QueueProfileRefresh(profile);
            }
        }

        private void DrawToolbar()
        {
            EditorGUILayout.BeginHorizontal(EditorStyles.toolbar);
            profile = (WorldAutotileProfile)EditorGUILayout.ObjectField(profile, typeof(WorldAutotileProfile), false, GUILayout.Width(position.width * 0.55f));

            if (GUILayout.Button("New Profile", EditorStyles.toolbarButton, GUILayout.Width(90f)))
            {
                CreateProfileAsset();
            }

            using (new EditorGUI.DisabledScope(profile == null))
            {
                if (GUILayout.Button("Create Authoring Layout", EditorStyles.toolbarButton, GUILayout.Width(155f)))
                {
                    WorldAutotileProfilePipeline.GenerateAuthoringLayout(profile);
                }
            }

            EditorGUILayout.EndHorizontal();
        }

        private void DrawPaletteTools()
        {
            EditorGUILayout.LabelField("Palette Tools", EditorStyles.boldLabel);
            EditorGUILayout.BeginVertical("box");

            EditorGUILayout.HelpBox("Create Authoring Layout builds a temporary editor-only prefab with marked grid sections. Edit tiles there, then use Build Profile From Layout to write the final WorldAutotileProfile.", MessageType.None);

            EditorGUILayout.PropertyField(serializedProfile.FindProperty("autoUpdatePaletteLayout"), new GUIContent("Auto Update Authoring Layout"));
            EditorGUILayout.PropertyField(serializedProfile.FindProperty("autoRefreshGeneratedWorld"), new GUIContent("Auto Refresh Generated World"));

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Create / Update Layout"))
            {
                WorldAutotileProfilePipeline.GenerateAuthoringLayout(profile);
            }

            using (new EditorGUI.DisabledScope(WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile) == null))
            {
                if (GUILayout.Button("Build Profile From Layout"))
                {
                    WorldAutotileProfilePipeline.BuildProfileFromAuthoringLayout(profile);
                }

                if (GUILayout.Button("Open Layout Prefab"))
                {
                    GameObject layout = WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile);
                    if (layout != null)
                    {
                        AssetDatabase.OpenAsset(layout);
                    }
                }
            }
            EditorGUILayout.EndHorizontal();

            using (new EditorGUI.DisabledScope(WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile) == null))
            {
                if (GUILayout.Button("Ping Layout Prefab"))
                {
                    GameObject layout = WorldAutotileProfilePipeline.LoadAuthoringLayoutAsset(profile);
                    if (layout != null)
                    {
                        EditorGUIUtility.PingObject(layout);
                        Selection.activeObject = layout;
                    }
                }
            }

            EditorGUILayout.LabelField("Layout Path", WorldAutotileProfilePipeline.GetAuthoringLayoutPath(profile));
            EditorGUILayout.EndVertical();
        }

        private void DrawValidation()
        {
            EditorGUILayout.LabelField("Profile Check", EditorStyles.boldLabel);
            EditorGUILayout.BeginVertical("box");

            List<string> missingShapes = GetMissingWallShapes();
            if (missingShapes.Count == 0)
            {
                EditorGUILayout.HelpBox("All wall variants are assigned. The generated palette layout will include every corner, side, and center tile.", MessageType.Info);
            }
            else
            {
                EditorGUILayout.HelpBox("Missing wall variants: " + string.Join(", ", missingShapes), MessageType.Warning);
            }

            int environmentCount = CountAssignedEnvironmentTiles();
            int prefabCount = CountAssignedRandomPrefabs();
            EditorGUILayout.LabelField("Background", profile.baseGroundTile != null ? profile.baseGroundTile.name : "Not assigned");
            EditorGUILayout.LabelField("Environment Tiles", environmentCount.ToString());
            EditorGUILayout.LabelField("Random Prefabs", prefabCount.ToString());
            EditorGUILayout.EndVertical();
        }

        private void DrawProfileFields()
        {
            EditorGUILayout.LabelField("Profile Assets", EditorStyles.boldLabel);
            EditorGUILayout.PropertyField(serializedProfile.FindProperty("baseGroundTile"), new GUIContent("Background Tile"));

            EditorGUILayout.Space(6f);
            EditorGUILayout.LabelField("Wall Variants", EditorStyles.miniBoldLabel);
            SerializedProperty walls = serializedProfile.FindProperty("wallTiles");
            DrawWallGrid(walls);

            EditorGUILayout.Space(6f);
            EditorGUILayout.PropertyField(serializedProfile.FindProperty("environmentTiles"), true);

            EditorGUILayout.Space(6f);
            EditorGUILayout.PropertyField(serializedProfile.FindProperty("randomPrefabs"), true);
        }

        private void DrawWallGrid(SerializedProperty walls)
        {
            DrawLabeledRow(walls, AutoTileShape.OuterTopLeft, AutoTileShape.Top, AutoTileShape.OuterTopRight);
            DrawLabeledRow(walls, AutoTileShape.Left, AutoTileShape.Center, AutoTileShape.Right);
            DrawLabeledRow(walls, AutoTileShape.OuterBottomLeft, AutoTileShape.Bottom, AutoTileShape.OuterBottomRight);
            DrawLabeledRow(walls, AutoTileShape.InnerTopLeft, AutoTileShape.InnerTopRight);
            DrawLabeledRow(walls, AutoTileShape.InnerBottomLeft, AutoTileShape.InnerBottomRight);
        }

        private static void DrawLabeledRow(SerializedProperty root, params AutoTileShape[] shapes)
        {
            EditorGUILayout.BeginHorizontal();
            for (int i = 0; i < shapes.Length; i++)
            {
                DrawLabeledCell(root, shapes[i]);
            }

            EditorGUILayout.EndHorizontal();
        }

        private static void DrawLabeledCell(SerializedProperty root, AutoTileShape shape)
        {
            SerializedProperty property = root.FindPropertyRelative(WorldAutotileEditorLabels.GetPropertyName(shape));
            EditorGUILayout.BeginVertical(GUILayout.MaxWidth(150f));
            EditorGUILayout.LabelField(WorldAutotileEditorLabels.GetShapeLabel(shape), EditorStyles.miniLabel);
            EditorGUILayout.PropertyField(property, GUIContent.none);
            EditorGUILayout.EndVertical();
        }

        private List<string> GetMissingWallShapes()
        {
            List<string> missing = new List<string>();
            for (int i = 0; i < WallShapeOrder.Length; i++)
            {
                AutoTileShape shape = WallShapeOrder[i];
                if (profile.wallTiles == null || profile.wallTiles.GetAssignedTile(shape) == null)
                {
                    missing.Add(shape.ToString());
                }
            }

            return missing;
        }

        private int CountAssignedEnvironmentTiles()
        {
            if (profile.environmentTiles == null)
            {
                return 0;
            }

            int count = 0;
            for (int i = 0; i < profile.environmentTiles.Count; i++)
            {
                if (profile.environmentTiles[i] != null && profile.environmentTiles[i].tile != null)
                {
                    count++;
                }
            }

            return count;
        }

        private int CountAssignedRandomPrefabs()
        {
            if (profile.randomPrefabs == null)
            {
                return 0;
            }

            int count = 0;
            for (int i = 0; i < profile.randomPrefabs.Count; i++)
            {
                if (profile.randomPrefabs[i] != null && profile.randomPrefabs[i].prefab != null)
                {
                    count++;
                }
            }

            return count;
        }

        private void CreateProfileAsset()
        {
            string path = EditorUtility.SaveFilePanelInProject("Create World Profile", "WorldAutotileProfile", "asset", "Choose where to save the tile profile.");
            if (string.IsNullOrEmpty(path))
            {
                return;
            }

            WorldAutotileProfile asset = CreateInstance<WorldAutotileProfile>();
            AssetDatabase.CreateAsset(asset, path);
            AssetDatabase.SaveAssets();
            profile = asset;
            serializedProfile = new SerializedObject(profile);
            Selection.activeObject = asset;
        }
    }
}
