using System.Linq;
using InfinityPBR.ModularCharacterHelper;
using Sirenix.Utilities;
using UnityEngine;
using VOID.Generic.Objects.Item.Events;
using VOID.Generic.Objects.Unit;
using VOID.Generic.Objects.Wearable;
using VOID.Generic.Objects.Wearable.Events;
using VOID.ScriptableObjects;

namespace VOID.Generic.Objects.Item
{
    [System.Serializable]
    public class WearableObjectState : ObjectComponent<WearableObject>
    {
        #region Initialize

        protected override void EventInitialize()
        {
            parent.itemEvents.onDroppedAfter.AddListener(OnDropped);
            parent.wearableEvents.onEquippedAfter.AddListener(OnEquip);
            parent.wearableEvents.onUnEquippedAfter.AddListener(OnUnEquip);
        }

        #endregion

        public UnitObject wearerUnit { get; private set; }
        public BasicStatus equipStatus { get; private set; }

        private GameObject _equipModelGameObject;

        private void OnDropped(DropEvent dropEvent)
        {
            EndEquipStatus();
            wearerUnit = null;
        }

        private void OnEquip(EquipEvent equipEvent)
        {
            wearerUnit = equipEvent.unit;
            ApplyEquipStatus();
            ShowEquipModel();
        }

        private void OnUnEquip(UnEquipEvent unEquipEvent)
        {
            EndEquipStatus();
            HideEquipModel();
            wearerUnit = null;
        }

        private void ApplyEquipStatus()
        {
            if (parent.wearableData.effects.Count <= 0) return;
            
            equipStatus = ScriptableObject.CreateInstance<BasicStatus>();
            equipStatus.name = $"EquipStatus: {wearerUnit.gameObject.name}";
            equipStatus.effects = parent.wearableData.effects;
            equipStatus.permanent = true;
            equipStatus.hidden = true;

            wearerUnit.statusManager.AddStatus(equipStatus, wearerUnit, false);
        }

        private void EndEquipStatus()
        {
            if (!equipStatus) return;
            
            equipStatus.Cancel();
            equipStatus = null;
        }

        private void ShowEquipModel()
        {
            var modularCharacter = wearerUnit.unitState.modularCharacter;
            if (!modularCharacter) return;
            
            // GameObject container for all parts
            _equipModelGameObject = new GameObject($"{parent.name} - equip model");
            _equipModelGameObject.transform.parent = wearerUnit.transform;
            
            // Find all matching parts that can be attached to unit's rig
            parent
                .GetComponentsInChildren<ModularPart>(true)
                .Where(modularPart => modularPart.avatar == modularCharacter.avatar)
                .Select(modularPart => Object.Instantiate(modularPart.gameObject).GetComponent<ModularPart>())
                .ForEach(modularPart =>
                {
                    modularPart.gameObject.transform.parent = _equipModelGameObject.transform;
                    modularCharacter.AttachPart(modularPart);
                });
        }

        private void HideEquipModel()
        {
            if (_equipModelGameObject) Object.Destroy(_equipModelGameObject);
            _equipModelGameObject = null;
        }
    }
}
