﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace JLGames.RocketDriver.Games.PanelManager
{
    internal sealed class PanelRegister : IPanelRegister
    {
        private readonly List<IPanelInfo> m_TempInfoList = new List<IPanelInfo>();
        private readonly List<IPanelInfo> m_InfoList = new List<IPanelInfo>();

        private readonly Dictionary<string, Transform> m_LayerMap = new Dictionary<string, Transform>();
        private string m_DefaultLayerName;

        private GameObject m_ContainerOrigin;
        private readonly Dictionary<string, BackgroundInfo> m_BackgroundMap = new Dictionary<string, BackgroundInfo>();
        private readonly Dictionary<string, RuntimeAnimatorController> m_AnimMap = new Dictionary<string, RuntimeAnimatorController>();

        public override string ToString()
        {
            return
                $"{{PanelSize={m_InfoList.Count}, ContainerSize={m_LayerMap.Count}, Default={m_DefaultLayerName}}}";
        }

        public void ClearRegister()
        {
            m_TempInfoList.Clear();
            m_LayerMap.Clear();
            m_InfoList.Clear();
            m_BackgroundMap.Clear();
            m_AnimMap.Clear();
        }

        public void RegisterPanelInfo(IPanelInfo info)
        {
            if (null == info) return;
            if (ContainsPanelInfo(info.Id))
            {
                throw new Exception($"RegisterPanel Error: id[{info.Id}] is repeated!");
            }

            m_InfoList.Add(info);
        }

        public void RegisterPanelInfo(string id, string bundleName, string assetPath)
        {
            var item = new PanelInfo(id, bundleName, assetPath);
            RegisterPanelInfo(item);
        }

        public void RegisterPanelInfo(string id, IPanelSettings settings, int maxDisplayNum, int extendType)
        {
            var item = new PanelInfo(id, settings, maxDisplayNum, extendType);
            RegisterPanelInfo(item);
        }

        public bool ContainsPanelInfo(string id)
        {
            return m_InfoList.FindIndex(item => item.Id == id) != -1;
        }

        public IPanelInfo GetPanelInfo(string id)
        {
            return m_InfoList.Find(info => info.Id == id);
        }

        public IPanelInfo[] GetPanelInfos(Predicate<IPanelInfo> match = null)
        {
            if (null == match) return m_InfoList.ToArray();
            m_TempInfoList.Clear();
            m_InfoList.ForEach((info =>
            {
                if (match.Invoke(info)) m_TempInfoList.Add(info);
            }));
            return m_TempInfoList.ToArray();
        }

        public void RegisterLayer(string layerName, Transform layer, bool @default)
        {
            if (string.IsNullOrEmpty(layerName) || null == layer) return;

            if (m_LayerMap.ContainsKey(layerName))
            {
                throw new Exception($"RegisterLayer Error: Name[{layerName}] is repeated!");
            }

            m_LayerMap.Add(layerName, layer);
            if (@default)
            {
                m_DefaultLayerName = layerName;
            }
        }

        public bool ContainsLayer(string name)
        {
            return m_LayerMap.ContainsKey(name);
        }

        public Transform GetPanelLayer(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return m_LayerMap.ContainsKey(m_DefaultLayerName)
                    ? m_LayerMap[m_DefaultLayerName]
                    : null;
            }

            return m_LayerMap.ContainsKey(name) ? m_LayerMap[name] : null;
        }

        public void RegisterBackground(string key, GameObject origin, string script)
        {
            if (string.IsNullOrEmpty(key) || null == origin) return;

            if (m_BackgroundMap.ContainsKey(key))
            {
                throw new Exception($"RegisterBackground Error: Key[{key}] is repeated!");
            }

            m_BackgroundMap.Add(key, new BackgroundInfo(key, origin, script));
        }

        public bool ContainsBackground(string key)
        {
            return m_BackgroundMap.ContainsKey(key);
        }

        public BackgroundInfo GetBackground(string key)
        {
            if (string.IsNullOrEmpty(key) || !m_BackgroundMap.ContainsKey(key)) return null;
            return m_BackgroundMap[key];
        }

        public void RegisterPanelContainer(GameObject container)
        {
            if (null == container)
            {
                throw new ArgumentNullException();
            }

            m_ContainerOrigin = container;
        }

        public GameObject PanelContainerOrigin => m_ContainerOrigin;

        public void RegisterAnimator(string key, RuntimeAnimatorController animator)
        {
            if (string.IsNullOrEmpty(key) || null == animator) return;

            if (m_AnimMap.ContainsKey(key))
            {
                throw new Exception($"RegisterAnimator Error: Key[{key}] is repeated!");
            }

            m_AnimMap.Add(key, animator);
        }

        public bool ContainsAnimator(string key)
        {
            return m_AnimMap.ContainsKey(key);
        }

        public RuntimeAnimatorController GetAnimator(string key)
        {
            if (string.IsNullOrEmpty(key) || !m_AnimMap.ContainsKey(key)) return null;
            return m_AnimMap[key];
        }
    }
}