using Connected.Models;
using Connected.Utilities;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using System.Numerics;

namespace Connected.Components;
public partial class NumberInput<NumberType> : InputBase where NumberType : INumber<NumberType>
{
	/// <summary>
	/// Step for up and down on numeric field
	/// Options: Any double number
	/// Default: 1
	/// </summary>
	[Parameter]
	public double Step { get; set; } = 1;

	/// <summary>
	/// Mouse wheel disable to prevent StepUp/StepDown on number filed
	/// Options: true, false
	/// Default: false
	/// </summary>
	[Parameter]
	public bool DisableMouseWheel { get; set; } = false;

	/// <summary>
	/// Increase 'Value' for the 'Step'
	/// </summary>
	/// <returns>'Value' increased for the 'Step' parameter</returns>
	private async Task StepUp()
	{
		try
		{
			var num = Helper.ConvertToType<double>(Value);

			num += Step;

			if (DecimalPlaces > 0)
				num = Math.Round(num, DecimalPlaces);
			Value = Helper.ConvertToType<NumberType>(num);
			

			if (IsError)
				ErrorText = string.Empty;
			isValueNull = false;
		}
		catch
		{
			ErrorText = "Error with step up!";
			isValueNull = true;
			Value = default;
		}

		await ValueChanged.InvokeAsync(Value);
	}

	/// <summary>
	/// Decrease 'Value' for the 'Step'
	/// </summary>
	/// <returns>'Value' decreased for the 'Step' parameter</returns>
	private async Task StepDown()
	{
		try
		{
			var num = Helper.ConvertToType<double>(Value);

			num -= Step;

			if (DecimalPlaces > 0)
				num = Math.Round(num, DecimalPlaces);

			Value = Helper.ConvertToType<NumberType>(num);

			if (IsError)
				ErrorText = string.Empty;
			isValueNull = false;
		}
		catch
		{
			ErrorText = "Error with step down!";
			Value = default;
			isValueNull = true;
		}

		await ValueChanged.InvokeAsync(Value);
	}

	/// <summary>
	/// Event triggered when mouse wheel is activated inside component
	/// </summary>
	/// <param name="args">WheelEventArgs argument</param>
	/// <returns>Doesnt return values just increasing/decreasing values</returns>
	protected async Task OnMouseWheel(WheelEventArgs args)
	{
		if (DisableMouseWheel)
			return;

		if (args.ShiftKey || Disabled || Readonly)
			return;

		if (args.DeltaY >= 0)
		{
			await StepDown();
		}
		else
		{
			await StepUp();
		}
	}

	private bool isValueNull { get; set; } = true;

	private bool IsValueSet()
	{
		bool result = false;
		if (Value is not null)
		{
			result= true;
		}
		return result;
	}

	//private string? _value;


	/// <summary>
	/// Value of any numeric type
	/// Options: any numeric type variable
	/// Default: null
	/// </summary>
	[Parameter]
	[EditorRequired]
	public NumberType? Value { get; set; } = default;
	//{
	//	get
	//	{
	//		if (string.IsNullOrEmpty(_value))
	//			return default;
	//		else
	//		{
	//			try
	//			{
	//				return Helper.ConvertToType<NumberType>(_value);
	//			} catch
	//			{
	//				return default;
	//			}
	//		}
	//	}
	//	set
	//	{
	//		Value = value;
	//	}
	//}

	/// <summary>
	/// Number of decimal places for Value. If set, Value is corrected when input looses focus
	/// Options: any integer number greater or equal 0
	/// Default: 0
	/// </summary>
	[Parameter]
	public int DecimalPlaces { get; set; } = 0;

	/// <summary>
	/// Value change event
	/// </summary>
	[Parameter]
	public EventCallback<NumberType?> ValueChanged { get; set; }

	//public async Task SetValueAsync(ChangeEventArgs args)
	//{
	//	if (args.Value is not null)
	//	{
	//		var newVal = args.Value.ToString()!;

	//		if (!newVal.Equals("0"))
	//		{
	//			if (newVal.ToString().Contains("-"))
	//				newVal = "-" + newVal.ToString().Replace("-", "");

	//			if (newVal.ToString().ToLower().Contains("e"))
	//				newVal = "e" + newVal.ToString().Replace("e", "");
	//		}

	//		if (string.IsNullOrEmpty(newVal))
	//			await ValueChanged.InvokeAsync(default);

	//		if (!newVal.Equals(_value))
	//			await ValueChanged.InvokeAsync(Helper.ConvertToType<NumberType>(newVal));
	//	}
	//}

	public async Task SetNumberValueAsync(ChangeEventArgs args)
	{
		if (args.Value is not null)
		{
			if (!string.IsNullOrEmpty(args.Value.ToString()))
			{
				Value = Helper.ConvertToType<NumberType>(args.Value);
				isValueNull = false;
			} else
			{
				isValueNull = true;
			}
			await ValueChanged.InvokeAsync(Value);
		}
	}

	public async Task Change(ChangeEventArgs args)
	{
		if (args.Value is not null)
			Value = AdjustDecimalPlaces(Helper.ConvertToType<NumberType>(args.Value));
		isValueNull = false;
		await ValueChanged.InvokeAsync(Value);
	}

	/// <summary>
	/// On keyboard key press event
	/// </summary>
	[Parameter]
	public EventCallback<KeyboardEventArgs> OnKeyDown { get; set; }

	//private bool CheckKey(string key)
	//{
	//	bool result;
	//	if (Helper.IsNumeric(key)) return true;
	//	switch (key.ToLower())
	//	{
	//		case "backspace":
	//		case "delete":
	//		case "arrowleft":
	//		case "arrowright":
	//		case "-":
	//			//case "e":
	//			{
	//				result = true;
	//				break;
	//			}
	//		default:
	//			{
	//				result = false;
	//				break;
	//			}
	//	}

	//	if ((key.Equals("-") || key.Equals("-")) && _value.Contains(key)) result = false;
	//	return result;
	//}

	//private bool _preventDefaultAction = true;
	//public async Task ChangeValue(KeyboardEventArgs args)
	//{
	//	_preventDefaultAction = true;
	//	if (args is not null)
	//	{
	//		var key = args.Key.ToString().ToLower();

	//		if (CheckKey(key))
	//		{
	//			_preventDefaultAction = false;

	//			await OnKeyDown.InvokeAsync(args);
	//		}
	//	}
	//	else
	//	{
	//		args.Key = null;
	//	}
	//}

	/// <summary>
	/// Method for adjusting decimal places provided with parameter
	/// </summary>
	/// <param name="value">Value whose decimal places we want to change</param>
	/// <returns>NumberType result with adjusted decimal places</returns>
	private NumberType? AdjustDecimalPlaces(NumberType? value)
	{
		var result = value;
		if (DecimalPlaces > 0)
		{
			double converted = Math.Round(Helper.ConvertToType<double>(result), DecimalPlaces);
			return Helper.ConvertToType<NumberType>(converted);
		}
		return result;
	}
	
	/// <summary>
	/// Clear event for user clear icon click. It clears the Value and set it to 
	/// </summary>
	/// <returns></returns>
	private async Task Clear()
	{
		//var val = Helper.ConvertToType<NumberType>(null);
		Value = default(NumberType);
		isValueNull = true;
		await ValueChanged.InvokeAsync(Value);
	}

	#region Lifecycle
	protected override async Task OnParametersSetAsync()
	{
		if (typeof(NumberType).Name.ToLower().Contains("int"))
		{
			if (Step - (int)Step > 0)
				Step = (int)Step;
			if (Step < 1)
				Step = 1;
		}
		await base.OnParametersSetAsync();
	}

	protected override void OnAfterRender(bool firstRender)
	{
		if (firstRender)
		{
			if (Value is not null)
			{
				if (!DecimalPlaces.Equals(Helper.GetDecimalPlaces(Value)))
				{
					Value = AdjustDecimalPlaces(Value);
					StateHasChanged();
				}
			}
		}
	}

	#endregion
}