using System;
using System.Collections.Generic;
using System.Linq;
#if UNITY_EDITOR
using UnityEngine;
#endif

namespace WS
{
	///<summary>组件</summary>
	public class WSComponent : Object, IDisposable
	{
		///<summary>组件ID</summary>
		public long InstanceId { get; private set; }

#if UNITY_EDITOR
		public static GameObject Global { get; } = GameObject.Find("/Init");

		public GameObject GameObject { get; protected set; }
#endif

		private WSComponent parent;
		///<summary>父组件</summary>
		public WSComponent Parent
		{
			get
			{
				return parent;
			}
			set
			{
				parent = value;

#if UNITY_EDITOR
				if (parent == null)
				{
					GameObject.transform.SetParent(Global.transform, false);
					return;
				}

				if (GameObject != null && parent.GameObject != null)
				{
					GameObject.transform.SetParent(parent.GameObject.transform, false);
				}
#endif
			}
		}

		///<summary>获取父组件</summary>
		public T GetParent<T>() where T : WSComponent
		{
			return Parent as T;
		}

		private bool isFromPool;
		///<summary>是否从ObjectPool中创建</summary>
		public bool IsFromPool
		{
			get { return isFromPool; }
			set
			{
				isFromPool = value;
				if (!isFromPool)
				{
					return;
				}
				if (InstanceId == 0)
				{
					InstanceId = IdGenerater.GenerateInstanceId();
				}
			}
		}

		///<summary>是否已经释放</summary>
		public bool IsDisposed { get { return InstanceId == 0; } }

		protected WSComponent()
		{
			InstanceId = IdGenerater.GenerateInstanceId();
#if UNITY_EDITOR
			GameObject = new GameObject();
			GameObject.name = GetType().Name;
			GameObject.transform.SetParent(Global.transform, false);
			GameObject.AddComponent<WSComponentView>().Component = this;
#endif
		}

#region -- 组件相关 --

		///<summary>挂在自己身上的组件</summary>
		private Dictionary<Type, WSComponent> ComponentDic = new Dictionary<Type, WSComponent>();

		///<summary>添加组件</summary>
		public virtual WSComponent AddComponent(WSComponent component)
		{
			Type type = component.GetType();
			if (ComponentDic.ContainsKey(type))
			{
				throw new Exception($"AddComponent, component already exist, id: {this.InstanceId}, component: {type.Name}");
			}

			component.Parent = this;

			ComponentDic.Add(type, component);

			return component;
		}

		///<summary>添加组件</summary>
		public virtual WSComponent AddComponent(Type type)
		{
			if (ComponentDic.ContainsKey(type))
			{
				throw new Exception($"AddComponent, component already exist, id: {InstanceId}, component: {type.Name}");
			}

			WSComponent component = ComponentFactory.CreateWithParent(type, this);

			ComponentDic.Add(type, component);

			return component;
		}

		///<summary>添加组件</summary>
		public virtual K AddComponent<K>() where K : WSComponent, new()
		{
			Type type = typeof(K);
			if (ComponentDic.ContainsKey(type))
			{
				throw new Exception($"AddComponent, component already exist, id: {InstanceId}, component: {typeof(K).Name}");
			}

			K component = ComponentFactory.CreateWithParent<K>(this);

			ComponentDic.Add(type, component);

			return component;
		}

		///<summary>添加组件</summary>
		public virtual K AddComponent<K, P1>(P1 p1) where K : WSComponent, new()
		{
			Type type = typeof(K);
			if (ComponentDic.ContainsKey(type))
			{
				throw new Exception($"AddComponent, component already exist, id: {InstanceId}, component: {typeof(K).Name}");
			}

			K component = ComponentFactory.CreateWithParent<K, P1>(this, p1);

			ComponentDic.Add(type, component);

			return component;
		}

		///<summary>添加组件</summary>
		public virtual K AddComponent<K, P1, P2>(P1 p1, P2 p2) where K : WSComponent, new()
		{
			Type type = typeof(K);
			if (ComponentDic.ContainsKey(type))
			{
				throw new Exception($"AddComponent, component already exist, id: {InstanceId}, component: {typeof(K).Name}");
			}

			K component = ComponentFactory.CreateWithParent<K, P1, P2>(this, p1, p2);

			ComponentDic.Add(type, component);

			return component;
		}

		///<summary>添加组件</summary>
		public virtual K AddComponent<K, P1, P2, P3>(P1 p1, P2 p2, P3 p3) where K : WSComponent, new()
		{
			Type type = typeof(K);
			if (ComponentDic.ContainsKey(type))
			{
				throw new Exception($"AddComponent, component already exist, id: {InstanceId}, component: {typeof(K).Name}");
			}

			K component = ComponentFactory.CreateWithParent<K, P1, P2, P3>(this, p1, p2, p3);

			ComponentDic.Add(type, component);

			return component;
		}

		///<summary>删除组件</summary>
		public virtual void RemoveComponent<K>() where K : WSComponent
		{
			if (IsDisposed)
			{
				return;
			}
			Type type = typeof(K);
			WSComponent component;
			if (!ComponentDic.TryGetValue(type, out component))
			{
				return;
			}

			ComponentDic.Remove(type);
			component.Dispose();
		}

		///<summary>删除组件</summary>
		public virtual void RemoveComponent(Type type)
		{
			if (IsDisposed)
			{
				return;
			}
			WSComponent component;
			if (!ComponentDic.TryGetValue(type, out component))
			{
				return;
			}

			ComponentDic.Remove(type);
			component.Dispose();
		}

		///<summary>获取组件</summary>
		public K GetComponent<K>() where K : WSComponent
		{
			WSComponent component;
			if (!ComponentDic.TryGetValue(typeof(K), out component))
			{
				return default(K);
			}
			return (K)component;
		}

		///<summary>获取组件</summary>
		public WSComponent GetComponent(Type type)
		{
			WSComponent component;
			if (!this.ComponentDic.TryGetValue(type, out component))
			{
				return null;
			}
			return component;
		}

		///<summary>获取所有组件</summary>
		public WSComponent[] GetComponents()
		{
			return ComponentDic.Values.ToArray();
		}

#endregion

		///<summary>释放</summary>
		public virtual void Dispose()
		{
			if (IsDisposed) return;

			// 触发Destroy事件
			Game.EventSystem.Destroy(this);
			Game.EventSystem.Remove(InstanceId);

			InstanceId = 0;

			foreach (WSComponent component in ComponentDic.Values)
			{
				component.Dispose();
			}
			ComponentDic.Clear();

			if (IsFromPool)
			{
				Game.ObjectPool.Recycle(this);
			}
			else
			{
#if UNITY_EDITOR
				if (GameObject != null)
				{
					UnityEngine.Object.Destroy(this.GameObject);
				}
#endif
			}
		}
	}
}