using Connected.Annotations;
using Connected.Extensions;
using Connected.Services;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

namespace Connected.Components;

public partial class Radio<T> : UIComponent, IDisposable
{
   [CascadingParameter(Name = "RightToLeft")] public bool RightToLeft { get; set; }

   protected string Classname =>
   new CssBuilder("radio")
       .AddClass($"disabled", Disabled)
       .AddClass($"radio-content-placement-{HorizontalAlignment}")

       .Build();

   protected string ButtonClassname =>
   new CssBuilder("button-root mud-icon-button")
       .AddClass($"ripple mud-ripple-radio", !DisableRipple && !Disabled)
       .AddClass($"{Color.ToDescription()}-text hover:mud-{Color.ToDescription()}-hover", UnCheckedColor == null || (UnCheckedColor != null && Checked == true))
       .AddClass($"{UnCheckedColor?.ToDescription()}-text hover:mud-{UnCheckedColor?.ToDescription()}-hover", UnCheckedColor != null && Checked == false)
       .AddClass($"radio-dense", Dense)
       .AddClass($"disabled", Disabled)
       .AddClass($"checked", Checked)
       .AddClass("error-text", RadioGroup?.HasErrors)
       .Build();

   protected string RadioIconsClassNames =>
   new CssBuilder("radio-icons")
       .AddClass($"checked", Checked)
       .Build();

   protected string IconClassName =>
   new CssBuilder("icon-root mud-svg-icon")
       .AddClass($"icon-size-{Size.ToDescription()}")
       .Build();

   protected string CheckedIconClassName =>
   new CssBuilder("icon-root mud-svg-icon mud-radio-icon-checked")
       .AddClass($"icon-size-{Size.ToDescription()}")
       .Build();

   protected string ChildSpanClassName =>
   new CssBuilder("radio-content mud-typography mud-typography-body1")
       .AddClass("error-text", RadioGroup.HasErrors)
       .Build();

   private IRadioGroup _parent;

   /// <summary>
   /// The parent Radio Group
   /// </summary>
   [CascadingParameter]
   internal IRadioGroup ParentGroup
   {
      get => _parent;
      set
      {
         _parent = value;
         if (_parent == null)
            return;
         _parent.CheckGenericTypeMatch(this);
         //MudRadioGroup<T>?.Add(this);
      }
   }

   internal RadioGroup<T> RadioGroup => (RadioGroup<T>)ParentGroup;
	
   /// <summary>
   /// The color of the component. It supports the theme colors.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Appearance)]
   public ThemeColor Color { get; set; } = ThemeColor.Default;

   /// <summary>
   /// The base color of the component in its none active/unchecked state. It supports the theme colors.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Appearance)]
   public ThemeColor? UnCheckedColor { get; set; } = null;

   /// <summary>
   /// The position of the child content.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Behavior)]
   public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.End;

   /// <summary>
   /// The value to associate to the button.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Behavior)]
   public T Option { get; set; }

   /// <summary>
   /// If true, compact padding will be applied.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Appearance)]
   public bool Dense { get; set; }

   /// <summary>
   /// The Size of the component.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Appearance)]
   public Size Size { get; set; } = Size.Medium;

   /// <summary>
   /// If true, disables ripple effect.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Appearance)]
   public bool DisableRipple { get; set; }

   /// <summary>
   /// If true, the button will be disabled.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Behavior)]
   public bool Disabled { get; set; }

   /// <summary>
   /// Child content of component.
   /// </summary>
   [Parameter]
   [Category(CategoryTypes.Radio.Behavior)]
   public RenderFragment ChildContent { get; set; }

   internal bool Checked { get; private set; }

   internal void SetChecked(bool value)
   {
      if (Checked != value)
      {
         Checked = value;
         StateHasChanged();
      }
   }

   public void Select()
   {
      RadioGroup?.SetSelectedRadioAsync(this).AndForget();
   }

   internal Task OnClick()
   {
      if (RadioGroup != null)
         return RadioGroup.SetSelectedRadioAsync(this);

      return Task.CompletedTask;
   }

   protected internal void HandleKeyDown(KeyboardEventArgs obj)
   {
      if (Disabled)
         return;
      switch (obj.Key)
      {
         case "Enter":
         case "NumpadEnter":
         case " ":
            Select();
            break;
         case "Backspace":
            RadioGroup.Reset();
            break;
      }
   }

   protected override async Task OnInitializedAsync()
   {
      await base.OnInitializedAsync();

      if (RadioGroup != null)
         await RadioGroup.RegisterRadioAsync(this);
   }

   public void Dispose()
   {
      RadioGroup?.UnregisterRadio(this);
      _keyInterceptor?.Dispose();
   }

   private IKeyInterceptor _keyInterceptor;
   [Inject] private IKeyInterceptorFactory _keyInterceptorFactory { get; set; }

   private string _elementId = "radio" + Guid.NewGuid().ToString().Substring(0, 8);

   protected override async Task OnAfterRenderAsync(bool firstRender)
   {
      if (firstRender)
      {
         _keyInterceptor = _keyInterceptorFactory.Create();
         await _keyInterceptor.Connect(_elementId, new KeyInterceptorOptions()
         {
            //EnableLogging = true,
            TargetClass = "button-root",
            Keys = {
                     new KeyOptions { Key=" ", PreventDown = "key+none", PreventUp = "key+none" }, // prevent scrolling page
                     new KeyOptions { Key="Enter", PreventDown = "key+none" },
                     new KeyOptions { Key="NumpadEnter", PreventDown = "key+none" },
                     new KeyOptions { Key="Backspace", PreventDown = "key+none" },
                 },
         });
      }
      await base.OnAfterRenderAsync(firstRender);
   }

}
