using Connected.Annotations;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;

namespace Connected.Components;

/// <summary>
/// Represents an option of a select or multi-select. To be used inside MudSelect.
/// </summary>
public partial class SelectItem<T> : SelectItemBase, IDisposable
{
   private String GetCssClasses() => new CssBuilder()
      .AddClass(AdditionalClassList)
      .Build();

   private ISelect _parent;
   internal string ItemId { get; } = "_" + Guid.NewGuid().ToString().Substring(0, 8);

   /// <summary>
   /// The parent select component
   /// </summary>
   [CascadingParameter]
   internal ISelect IMudSelect
   {
      get => _parent;
      set
      {
         _parent = value;
         if (_parent == null)
            return;
         _parent.CheckGenericTypeMatch(this);
         if (Select == null)
            return;
         bool isSelected = Select.Add(this);
         if (_parent.MultiSelection)
         {
            Select.SelectionChangedFromOutside += OnUpdateSelectionStateFromOutside;
            InvokeAsync(() => OnUpdateSelectionStateFromOutside(Select.SelectedValues));
         }
         else
         {
            IsSelected = isSelected;
         }
      }
   }

   private IShadowSelect _shadowParent;
   private bool _isSelected;

   [CascadingParameter]
   internal IShadowSelect ParentShadow
   {
      get => _shadowParent;
      set
      {
         _shadowParent = value;
         ((Select<T>)_shadowParent)?.RegisterShadowItem(this);
      }
   }

   /// <summary>
   /// Select items with HideContent==true are only there to register their RenderFragment with the select but
   /// wont render and have no other purpose!
   /// </summary>
   [CascadingParameter(Name = "HideContent")]
   internal bool HideContent { get; set; }

   internal Select<T> Select => (Select<T>)IMudSelect;

   private void OnUpdateSelectionStateFromOutside(IEnumerable<T> selection)
   {
      if (selection == null)
         return;
      var old_is_selected = IsSelected;
      IsSelected = selection.Contains(Value);
      if (old_is_selected != IsSelected)
         InvokeAsync(StateHasChanged);
   }

   /// <summary>
   /// A user-defined option that can be selected
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.FormComponent.Behavior)]
   public T Value { get; set; }

   /// <summary>
   /// Mirrors the MultiSelection status of the parent select
   /// </summary>
   protected bool MultiSelection
   {
      get
      {
         if (Select == null)
            return false;
         return Select.MultiSelection;
      }
   }

   /// <summary>
   /// Selected state of the option. Only works if the parent is a mulit-select
   /// </summary>
   internal bool IsSelected
   {
      get => _isSelected;
      set
      {
         _isSelected = value;
      }
   }

   /// <summary>
   /// The checkbox icon reflects the multi-select option's state
   /// </summary>
   protected string CheckBoxIcon
   {
      get
      {
         if (!MultiSelection)
            return null;
         return IsSelected ? Icons.Material.Filled.CheckBox : Icons.Material.Filled.CheckBoxOutlineBlank;
      }
   }

   protected string DisplayString
   {
      get
      {
         var converter = Select?.Converter;
         if (converter == null)
            return $"{Value}";
         return converter.Convert(Value);
      }
   }

   private void OnClicked()
   {
      if (MultiSelection)
         IsSelected = !IsSelected;

      Select?.SelectOption(Value);
      InvokeAsync(StateHasChanged);
   }

   public void Dispose()
   {
      try
      {
         Select?.Remove(this);
         ((Select<T>)_shadowParent)?.UnregisterShadowItem(this);
      }
      catch (Exception) { }
   }
}
