using System.Diagnostics.CodeAnalysis;
using System.Windows.Input;
using Connected.Annotations;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

namespace Connected.Components;

public partial class Menu : UIComponent, IActivatable
{
	protected string Classname =>
	new CssBuilder("menu")
	.AddClass(AdditionalClassList)
	.Build();

	protected string ActivatorClassname =>
	new CssBuilder("menu-activator")
	.AddClass("disabled", Disabled)
	.Build();

	private bool _isOpen;
	private bool _isMouseOver = false;

	[Parameter]
	[Category(CategoryTypes.Menu.Behavior)]
	public string Label { get; set; }

	/// <summary>
	/// User class names for the list, separated by space
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public string ListClass { get; set; }

	/// <summary>
	/// User class names for the popover, separated by space
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public string PopoverClass { get; set; }

	/// <summary>
	/// Glyph to use if set will turn the button into a MudIconButton.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Behavior)]
	public string Icon { get; set; }

	/// <summary>
	/// The color of the icon. It supports the theme colors.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Appearance)]
	public ThemeColor IconColor { get; set; } = ThemeColor.Inherit;

	/// <summary>
	/// Glyph placed before the text if set.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Behavior)]
	public string StartIcon { get; set; }

	/// <summary>
	/// Glyph placed after the text if set.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Behavior)]
	public string EndIcon { get; set; }

	/// <summary>
	/// The color of the button. It supports the theme colors.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Appearance)]
	public ThemeColor Color { get; set; } = ThemeColor.Default;

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

	/// <summary>
	/// The button variant to use.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Appearance)]
	public Variant Variant { get; set; } = Variant.Text;


	/// <summary>
	/// If true, compact vertical padding will be applied to all menu items.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public bool Dense { get; set; }

	/// <summary>
	/// If true, the list menu will be same width as the parent.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public bool FullWidth { get; set; }

	/// <summary>
	/// Sets the maxheight the menu can have when open.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public int? MaxHeight { get; set; }

	/// <summary>
	/// If true, instead of positioning the menu at the left upper corner, position at the exact cursor location.
	/// This makes sense for larger activators
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupBehavior)]
	public bool PositionAtCursor { get; set; }

	/// <summary>
	/// If true, instead of positioning the menu at the left upper corner, position at the exact cursor location.
	/// This makes sense for larger activators
	/// </summary>
	[Obsolete("Use PositionAtCursor instead.", true)]
	[Parameter]
	public bool PositionAtCurser
	{
		get => PositionAtCursor;
		set => PositionAtCursor = value;
	}

	/// <summary>
	/// Place a MudButton, a MudIconButton or any other component capable of acting as an activator. This will
	/// override the standard button and all parameters which concern it.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Behavior)]
	public RenderFragment ActivatorContent { get; set; }

	/// <summary>
	/// Specify the activation event when ActivatorContent is set
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Behavior)]
	public MouseEvent ActivationEvent { get; set; } = MouseEvent.LeftClick;

	/// <summary>
	/// Set the anchor origin point to determen where the popover will open from.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public Origin AnchorOrigin { get; set; } = Origin.TopLeft;

	/// <summary>
	/// Sets the transform origin point for the popover.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public Origin TransformOrigin { get; set; } = Origin.TopLeft;

	/// <summary>
	/// Sets the direction the select menu will start from relative to its parent.
	/// </summary>
	[ExcludeFromCodeCoverage]
	[Obsolete("Use AnchorOrigin or TransformOrigin instead.", true)]
	[Parameter] public Direction Direction { get; set; } = Direction.Bottom;

	/// <summary>
	/// If true, the select menu will open either before or after the input depending on the direction.
	/// </summary>
	[ExcludeFromCodeCoverage]
	[Obsolete("Use AnchorOrigin or TransformOrigin instead.", true)]
	[Parameter] public bool OffsetY { get; set; }

	/// <summary>
	/// If true, the select menu will open either above or bellow the input depending on the direction.
	/// </summary>
	[ExcludeFromCodeCoverage]
	[Obsolete("Use AnchorOrigin or TransformOrigin instead.", true)]
	[Parameter] public bool OffsetX { get; set; }

	/// <summary>
	/// Set to true if you want to prevent page from scrolling when the menu is open
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupAppearance)]
	public bool LockScroll { get; set; }

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

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

	/// <summary>
	/// If true, no drop-shadow will be used.
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.Appearance)]
	public bool DisableElevation { get; set; }

	#region Obsolete members from previous MudButtonBase inherited structure

	[ExcludeFromCodeCoverage]
	[Obsolete("Linking is not supported. MudMenu is not a MudBaseButton anymore.", true)]
	[Parameter] public string Link { get; set; }

	[ExcludeFromCodeCoverage]
	[Obsolete("Linking is not supported. MudMenu is not a MudBaseButton anymore.", true)]
	[Parameter] public string Target { get; set; }

	[ExcludeFromCodeCoverage]
	[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
	[Parameter] public string HtmlTag { get; set; } = "button";

	[ExcludeFromCodeCoverage]
	[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
	[Parameter] public ButtonType ButtonType { get; set; }

	[ExcludeFromCodeCoverage]
	[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
	[Parameter] public ICommand Command { get; set; }

	[ExcludeFromCodeCoverage]
	[Obsolete("MudMenu is not a MudBaseButton anymore.", true)]
	[Parameter] public object CommandParameter { get; set; }

	#endregion

	/// <summary>
	/// Add menu items here
	/// </summary>
	[Parameter]
	[Category(CategoryTypes.Menu.PopupBehavior)]
	public RenderFragment ChildContent { get; set; }

	public string PopoverStyle { get; set; }

	public void CloseMenu()
	{
		_isOpen = false;
		_isMouseOver = false;
		PopoverStyle = null;
		StateHasChanged();
	}

	public void OpenMenu(EventArgs args)
	{
		if (Disabled)
			return;
		if (PositionAtCursor) SetPopoverStyle((MouseEventArgs)args);
		_isOpen = true;
		StateHasChanged();
	}

	// Sets the popover style ONLY when there is an activator
	private void SetPopoverStyle(MouseEventArgs args)
	{
		AnchorOrigin = Origin.TopLeft;
		PopoverStyle = $"margin-top: {args?.OffsetY.ToPx()}; margin-left: {args?.OffsetX.ToPx()};";
	}

	public void ToggleMenu(MouseEventArgs args)
	{
		if (Disabled)
			return;
		if (ActivationEvent == MouseEvent.LeftClick && args.Button != 0 && !_isOpen)
			return;
		if (ActivationEvent == MouseEvent.RightClick && args.Button != 2 && !_isOpen)
			return;
		if (_isOpen)
			CloseMenu();
		else
			OpenMenu(args);
	}

	public void ToggleMenuTouch(TouchEventArgs args)
	{
		if (Disabled)
		{
			return;
		}

		if (_isOpen)
		{
			CloseMenu();
		}
		else
		{
			OpenMenu(args);
		}
	}

	/// <summary>
	/// Implementation of IActivatable.Activate, toggles the menu.
	/// </summary>
	/// <param name="activator"></param>
	/// <param name="args"></param>
	public void Activate(object activator, MouseEventArgs args)
	{
		ToggleMenu(args);
	}

	public void MouseEnter(MouseEventArgs args)
	{
		_isMouseOver = true;

		if (ActivationEvent == MouseEvent.MouseOver)
		{
			OpenMenu(args);
		}
	}

	public async void MouseLeave()
	{
		_isMouseOver = false;

		await Task.Delay(100);

		if (ActivationEvent == MouseEvent.MouseOver && _isMouseOver == false)
		{
			CloseMenu();
		}
	}
}
