/*           INFINITY CODE          */
/*     https://infinity-code.com    */

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

namespace InfinityCode.TreeTools.Editors
{
    internal class TerrainWrapper
    {
        public TerrainData terrainData;
        public Bounds bounds;
        public List<TreePrototype> treePrototypes;
        public List<TreeInstance> treeInstances;
        public Vector3 size;
        private Vector3 terrainPosition;

        public bool changed { get; private set; }

        public TerrainWrapper(Terrain terrain)
        {
            terrainData = terrain.terrainData;
            terrainPosition = terrain.transform.position;
            size = terrainData.size;
            bounds = new Bounds(terrain.transform.position + size / 2, size);
        }

        public void Add(GameObject go, int action)
        {
            string path = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(go);
            GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(path);

            if (!changed)
            {
                treePrototypes = terrainData.treePrototypes.ToList();
                treeInstances = terrainData.treeInstances.ToList();
                changed = true;
            }

            int prototypeIndex = -1;
            for (int i = 0; i < treePrototypes.Count; i++)
            {
                if (treePrototypes[i].prefab == prefab)
                {
                    prototypeIndex = i;
                    break;
                }
            }

            if (prototypeIndex == -1)
            {
                TreePrototype prototype = new TreePrototype { prefab = prefab };
                prototypeIndex = treePrototypes.Count;
                treePrototypes.Add(prototype);
            }

            Transform t = go.transform;
            Transform pt = prefab.transform;

            Vector3 pos = t.position - terrainPosition;
            pos.x /= size.x;
            pos.y /= size.y;
            pos.z /= size.z;

            TreeInstance instance = new TreeInstance
            {
                prototypeIndex = prototypeIndex,
                position = pos,
                rotation = t.rotation.eulerAngles.y * Mathf.Deg2Rad,
                heightScale = t.localScale.y / pt.localScale.y,
                widthScale = (t.localScale.x / pt.localScale.x + t.localScale.z / pt.localScale.z) / 2,
                color = Color.white,
                lightmapColor = Color.white
            };

            treeInstances.Add(instance);

            if (action == 0)
            {
                UndoEx.DestroyObjectImmediate(go);
            }
            else if (action == 2)
            {
                UndoEx.RecordObject(go, "Disable GameObject");
                go.SetActive(false);
            }
        }

        public bool Contain(Vector3 position)
        {
            return bounds.Contains(position);
        }

        public void Dispose()
        {
            terrainData = null;
            treePrototypes = null;
            treeInstances = null;
        }

        public void Finish()
        {
            if (changed)
            {
                UndoEx.RecordObject(terrainData, "Append Tree Instance");
                bool logEnabled = Debug.unityLogger.logEnabled;
                Debug.unityLogger.logEnabled = false;
                terrainData.treePrototypes = treePrototypes.ToArray();
                terrainData.SetTreeInstances(treeInstances.ToArray(), false);
                Debug.unityLogger.logEnabled = logEnabled;
            }

            Dispose();
        }
    }
}