using System.Collections.Generic;
using Patterns_And_Principles.Patterns.Object_Pool_Pattern.BasicPool.Script.Interface;
using UnityEngine;

namespace Patterns_And_Principles.Patterns.Object_Pool_Pattern.BasicPool.Script
{
    public class ObjectPool<T> where T : Component
    {
        private Queue<T> _pool = new Queue<T>();
        private T _prefab;
        private Transform _parent;
        private int _maxSize;
        private bool _autoExpand;

        public ObjectPool(T prefab, Transform parent = null, int maxSize = 0, bool autoExpand = true)
        {
            this._prefab = prefab;
            this._parent = parent;
            this._maxSize = maxSize;
            this._autoExpand = autoExpand;
            for (int i = 0; i < maxSize; i++)
            {
                CreateObject();
            }
        }

        private T CreateObject()
        {
            T obj = GameObject.Instantiate(_prefab, _parent);
            obj.gameObject.SetActive(false);
            _pool.Enqueue(obj);
            return obj;
        }

        #region Public Functions

        public T Get()
        {
            if (_pool.Count == 0)
            {
                return _autoExpand ? CreateObject() : null;
            }

            T obj = _pool.Dequeue();
            obj.gameObject.SetActive(true);
            if (obj.TryGetComponent<IPoolable>(out var poolable))
            {
                poolable.OnSpawn();
            }

            return obj;
        }
        public void Release(T obj)
        {
            if (obj.TryGetComponent<IPoolable>(out var poolable))
            {
                poolable.OnDespawn();
            }
            obj.gameObject.SetActive(false);
            _pool.Enqueue(obj);
        }

        #endregion
    }
}