using System.Threading;
using TagFighter.Events;
using TagFighter.Resources;
using UnityEngine;

namespace TagFighter.UI
{
    public class AttributeNavigator : MonoBehaviour
    {
        [SerializeField] EventAggregator _eventAggregator;
        [SerializeField] AttributeUI _attributeUIPrefab;
        PartyMember _selectedPartyMember;
        CancellationTokenSource _cancellationSource;
        PawnSheetState _pawnSheetState = PawnSheetState.Uninit;

        protected void Awake() {
            _eventAggregator.UnitSelected += OnUnitSelected;
            _eventAggregator.PawnSheetShowed += OnPawnSheetShowed;
            _eventAggregator.PawnSheetHid += OnPawnSheetHid;
        }

        protected void OnDestroy() {
            _eventAggregator.UnitSelected -= OnUnitSelected;
            _eventAggregator.PawnSheetShowed -= OnPawnSheetShowed;
            _eventAggregator.PawnSheetHid -= OnPawnSheetHid;
            if (_cancellationSource != null) {
                _cancellationSource.Cancel();
                _cancellationSource.Dispose();
            }
        }

        void RegisterToResource(IWatchableResource resource, IResourceViewer resourceViewer, CancellationToken cancellationToken) {
            void Handler(object sender, ResourceChangeArgs e) {
                resourceViewer.UpdateView(e);
            }

            void UnregisterHandler() {
                resource.ResourceChanged -= Handler;
            }

            resource.ResourceChanged += Handler;
            cancellationToken.Register(UnregisterHandler);
            resourceViewer.UpdateView(resource.Status);
        }

        void OnPawnSheetHid(object sender, EventAggregator.PawnSheetHidEventArgs e) {
            _pawnSheetState = PawnSheetState.Hidden;
            _cancellationSource?.Cancel();
        }

        void OnPawnSheetShowed(object sender, EventAggregator.PawnSheetShowedEventArgs e) {
            _pawnSheetState = PawnSheetState.Shown;
            if (_selectedPartyMember != null) {
                _cancellationSource?.Cancel();
                CreateAttributeList(_selectedPartyMember);
            }
        }

        void OnUnitSelected(object sender, UnitActionEventArgs e) {
            if (e.UnitTransform.TryGetComponent<PartyMember>(out var partyMember) && _selectedPartyMember != partyMember) {
                _selectedPartyMember = partyMember;
                if (_pawnSheetState == PawnSheetState.Shown) {
                    _cancellationSource?.Cancel();
                    CreateAttributeList(_selectedPartyMember);
                }
            }
        }

        void CreateAttributeList(PartyMember partyMember) {
            var currentAttributeIndex = 0;

            _cancellationSource = new();
            foreach (var resource in partyMember.GetComponents<IWatchableResource>()) {
                var attributeUI = currentAttributeIndex < transform.childCount ?
                                  transform.GetChild(currentAttributeIndex).GetComponent<AttributeUI>() :
                                  Instantiate(_attributeUIPrefab, transform).GetComponent<AttributeUI>();

                attributeUI.SetName(resource.GetType().Name);
                RegisterToResource(resource, attributeUI, _cancellationSource.Token);

                attributeUI.gameObject.SetActive(true);
                currentAttributeIndex++;
            }

            for (; currentAttributeIndex < transform.childCount; currentAttributeIndex++) {
                transform.GetChild(currentAttributeIndex).gameObject.SetActive(false);
            }
        }
    }
}