using System;
using Sirenix.OdinInspector;
using UnityEngine.UIElements;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Abstract.Events;
using VOID.Generic.Objects.Unit;

namespace VOID.UserInterface.Game.Party
{
    /// <summary>
    /// Manages all visuals inside <see cref="UnitObject"/> portrait, including: image, border and healthbar
    /// </summary>
    public class UnitPortraitUI
    {
        [ShowInInspector, ReadOnly] public UnitObject unit { get; private set; }

        public event Action<UnitObject> OnClick;

        // Visual Elements
        public VisualElement templateElement { get; private set; }
        private Button _portrait;
        private ProgressBar _healthBar;
        private Label _healthLabel;

        /// <summary>
        /// Initializes <see cref="UnitPortraitUI"/> on existing potrait visual element.
        /// </summary>
        /// <param name="unitPortraitTemplate">Existing template to use for this portrait</param>
        public void Init(VisualElement unitPortraitTemplate)
        {
            // Find all important elements
            templateElement = unitPortraitTemplate;
            _portrait = templateElement.Q<Button>("portrait");
            _healthBar = templateElement.Q<ProgressBar>("health-bar");
            _healthLabel = templateElement.Q<Label>("health-label");
            
            templateElement.RegisterCallback(new EventCallback<MouseDownEvent>(_ => OnClick?.Invoke(unit)), TrickleDown.TrickleDown);

            // Binding component to element
            templateElement.dataSource = this;
            templateElement.pickingMode = PickingMode.Position;
        }

        /// <summary>
        /// Initializes completly new <see cref="UnitPortraitUI"/> inside given parent.
        /// </summary>
        /// <param name="parentElement">Create new potratit as child in given parent.</param>
        public void InitNew(VisualElement parentElement)
        {
            // Find all important elements
            var newTemplateElement = GameUI.current.unitPortraitTemplate.CloneTree().contentContainer;
            newTemplateElement.AddToClassList("unit-portrait");
            newTemplateElement.AddToClassList("unit-portrait-small");
            parentElement.Add(newTemplateElement);
            Init(newTemplateElement);
        }

        /// <summary>
        /// Display given <see cref="UnitObject"/> in this portrait.
        /// </summary>
        public void SetUnit(UnitObject unitToSet)
        {
            // Remove everything about previous Unit
            UnsetUnit(); 

            // New Unit assigned - start listeners and wait
            unit = unitToSet;
            unit.basicEvents.onCurrentResourceChange.AddListener(OnBasicResourceChange);
            
            // Set Unit's portrait
            _portrait.style.backgroundImage = new StyleBackground(unit.basicData.image);

            UnitPortraitHealthChange();
        }

        /// <summary>
        /// Clear currently displaying <see cref="UnitObject"/> in this portrait.
        /// </summary>
        public void UnsetUnit()
        {
            // There is no unit currently
            if (!unit) return;

            // Remove all listeners, then remove assigned Unit
            unit.basicEvents.onCurrentResourceChange.RemoveListener(OnBasicResourceChange);
            unit = null;
            
            // Make UI invisible and unset portrait
            _portrait.style.backgroundImage = null;
        }

        /// <summary>
        /// Completly destroy this potratit.
        /// </summary>
        public void Destroy()
        {
            unit.basicEvents.onCurrentResourceChange.RemoveListener(OnBasicResourceChange);
            templateElement.parent.Remove(templateElement);
        }

        private void OnBasicResourceChange(BasicResourceChangeEvent basicResourceChangeEvent)
        {
            // Update HealthBar length
            if (basicResourceChangeEvent.type is BasicResourceType.Health)
            {
                UnitPortraitHealthChange();
            }
        }

        private void UnitPortraitHealthChange()
        {
            // Update HealthBar length
            _healthBar.value = unit.basicData.currentResources.Get(BasicResourceType.Health) / unit.basicData.maxResources.Get(BasicResourceType.Health) * 100;

            // Update HealthBar label
            _healthLabel.text = $"{unit.basicData.currentResources.Get(BasicResourceType.Health)}/{unit.basicData.maxResources.Get(BasicResourceType.Health)}";
        }
    }
}
