﻿using JLGames.RocketDriver.Actions.Utils;
using UnityEngine;

namespace JLGames.RocketDriver.Actions.Layer
{
    [RequireComponent(typeof(LayerConfig))]
    public class LayerManager : MonoBehaviour, ILayerManager
    {
        [SerializeField] private bool m_AllowDuplicate = false;
        [SerializeField] private GameObject m_LayerOrigin;
        [SerializeField] private Transform m_LayerContainer;
        public Transform LayerRootContainer => m_LayerContainer == null ? transform : m_LayerContainer;

        public void SetRootContainer(Transform root)
        {
            m_LayerContainer = root;
        }

        public void SetLayerPrefab(GameObject original)
        {
            m_LayerOrigin = original;
        }

        public void InitLayers()
        {
            var config = GetComponent<LayerConfig>();
            if (null == config) return;
            var layerInfos = config.GetSortedLayers();
            if (null == layerInfos || layerInfos.Length == 0) return;
            foreach (var layerInfo in layerInfos)
            {
                var layer = GenLayer(layerInfo.Name);
                if (null == layer) layer = GetLayerByName(LayerRootContainer, layerInfo.Name);
                layer.SetSiblingIndex(layerInfo.Priority);
            }
        }

        public Transform GenLayer(string layerName)
        {
            return GenLayerAt(LayerRootContainer, layerName);
        }

        public Transform GenLayer(string layerName, int siblingIndex)
        {
            return GenLayerAt(LayerRootContainer, layerName, siblingIndex);
        }

        public Transform[] GenLayers(string[] layerNames)
        {
            if (null == layerNames || layerNames.Length == 0)
            {
                return null;
            }

            var layers = new Transform[layerNames.Length];
            for (var index = 0; index < layerNames.Length; index++)
            {
                var layerName = layerNames[index];
                var layer = GenLayer(layerName);
                layers[index] = layer;
            }

            return layers;
        }

        public Transform GenLayerAt(string rootNameChain, string layerName)
        {
            if (string.IsNullOrEmpty(rootNameChain)) return null;
            var container = GetLayerByNamechain(LayerRootContainer, rootNameChain);
            if (null == container) return null;
            var layer = GenNewLayer(layerName);
            if (null == layer) return null;
            TransformUtil.AddChildTo(layer, container);
            return layer;
        }


        public Transform GenLayerAt(string rootNameChain, string layerName, int siblingIndex)
        {
            var layer = GenLayerAt(rootNameChain, layerName);
            if (null == layer) return null;
            layer.SetSiblingIndex(siblingIndex);
            return layer;
        }

        public Transform GenLayerAt(Transform container, string layerName)
        {
            var layer = GenNewLayer(layerName);
            if (null == layer) return null;
            TransformUtil.AddChildTo(layer, container);
            return layer;
        }

        public Transform GenLayerAt(Transform container, string layerName, int siblingIndex)
        {
            var layer = GenLayerAt(container, layerName);
            if (null == layer) return null;
            layer.SetSiblingIndex(siblingIndex);
            return layer;
        }

        public bool ContainsLayer(string nameOrChain)
        {
            return !string.IsNullOrEmpty(nameOrChain) && ContainsLayerByNamechain(LayerRootContainer, nameOrChain);
        }

        public bool ContainsLayer(Transform container, string nameOrChain)
        {
            return !string.IsNullOrEmpty(nameOrChain) && ContainsLayerByNamechain(container, nameOrChain);
        }

        public Transform GetLayer(string nameOrChain, bool useName)
        {
            return GetLayer(LayerRootContainer, nameOrChain, useName);
        }

        public Transform GetLayer(Transform root, string nameOrChain, bool useName)
        {
            return useName ? GetLayerByName(root, nameOrChain) : GetLayerByNamechain(root, nameOrChain);
        }

        // -----------------------------------------

        private Transform GenNewLayer(string layerName)
        {
            if (!m_AllowDuplicate && GetLayerByName(LayerRootContainer, layerName) != null) return null;

            GameObject layer;
            if (null != m_LayerOrigin)
            {
                layer = Instantiate(m_LayerOrigin);
            }
            else
            {
                layer = new GameObject();
            }

            layer.name = layerName;
            return layer.transform;
        }

        private bool ContainsLayerByName(Transform root, string layerName)
        {
            return root.Find(layerName) != null;
        }

        private bool ContainsLayerByNamechain(Transform root, string nameChain)
        {
            return GetLayerByNamechain(root, nameChain) != null;
        }

        private Transform GetLayerByName(Transform root, string layerName)
        {
            return root.Find(layerName);
        }

        private Transform GetLayerByNamechain(Transform root, string nameChain)
        {
            var rs = TransformUtil.GetSubTransform(root, nameChain);
            return null == rs ? null : rs;
        }
    }
}