using System;
using System.Collections.Generic;
using System.Linq;
using Assets.Source.Patterns.ObjectPool;
using Assets.Source.Patterns.ScriptableObjects;
using Assets.Source.Utils;
using UnityEngine;

namespace Assets.Source.CommonWorkers
{
    [Serializable]
    public class AttachedObject
    {
        public Transform ThisTransform;
        public Transform TargetTransform;
        public Vector3 Offset;
        public bool CopyRotation;
        public bool UnattachIfTransformDisabled = true;
    }
    
    public class WorkerTransformAttachment : RuntimeSet<AttachedObject>
    {
        private readonly List<AttachedObject> _objectsToRemove = new List<AttachedObject>();
        
        protected override void VInit()
        {
            base.VInit();

            // TODO optimize
            PoolManager.Instance.OnAfterRelease += HandlePoolObjectRelease;
        }

        protected override void VFixedUpdate()
        {
            base.VFixedUpdate();
            foreach (var attachedObj in Items)
            {
                var t = attachedObj.ThisTransform;
                if (t == null ||
                    attachedObj.UnattachIfTransformDisabled && !t.gameObject.activeInHierarchy ||
                    attachedObj.TargetTransform == null)
                {
                    _objectsToRemove.Add(attachedObj);
                    continue;
                }

                var targetPos = attachedObj.TargetTransform.position + attachedObj.Offset;
                t.position = targetPos;
                if (attachedObj.CopyRotation)
                    t.rotation = attachedObj.TargetTransform.rotation;
            }

            foreach (var o in _objectsToRemove)
                Remove(o);
                //UnattachTransform(o.TargetTransform);
            _objectsToRemove.Clear();
        }
        
        public void AttachTransform(AttachedObject attachedObj)
        {
            // если таргет задизейблен, то не аттачим, потому что он может быть в пуле. 
            // то есть когда заспавнится из пула, этот эффект скакнет к нему, что есть плохо
            if (!attachedObj.TargetTransform.gameObject.activeInHierarchy)
                return;
            
            Unattach(attachedObj);
            Add(attachedObj);
        }

        public void AttachTransform(Transform thisTransform, Transform targetTransform, Vector3 offset, bool unattachOnDisable = true)
        {
            var attachedObj = new AttachedObject
            {
                ThisTransform = thisTransform,
                TargetTransform = targetTransform,
                Offset = offset,
                UnattachIfTransformDisabled = unattachOnDisable
            };
            AttachTransform(attachedObj);
        }

        public void AttachTransform(Transform thisTransform, Transform targetTransform, bool unattachOnDisable = true)
        {
            var attachedObj = new AttachedObject
            {
                TargetTransform = targetTransform,
                UnattachIfTransformDisabled = unattachOnDisable
            };
            AttachTransform(attachedObj);
        }

        public void Unattach(AttachedObject attachedObj)
        {
            Remove(attachedObj);
        }

        public void UnattachTransform(Transform t)
        {
            var attachedObj = Items.FirstOrDefault(o => o.ThisTransform == t);
            if (attachedObj != null)
                Remove(attachedObj);
        }

        public void UnattachAllFrom(Transform from)
        {
            foreach (var attachedObj in Items)
            {
                if (attachedObj.TargetTransform == from)
                    _objectsToRemove.Add(attachedObj);
            }
        }

        private void HandlePoolObjectRelease(IPoolObject poolObj)
        {
            UnattachAllFrom(poolObj.gameObject.transform);
        }
    }
}