/*
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC.
 */

using CommunityToolkit.Maui.Behaviors;

using DXLib.UI.Gestures;
using DXLib.Utils;

namespace DXLib.UI.Control.Button;

/*
 * Wrapper for MAUI Image providing a tappable SVG icon. The button has an icon color and optional background color,
 * shadow, and border. Visual states are handled for down, tap, and press. A sticky state is also supported where the
 * button must be programatically reset following a tap.
 */
public class DXIconButton : DXBorderGestures
{
	/* Constants */
	private const double DefaultPad = 5;

	// Opacities
	private const double DisabledOpacity = 0.20;
	private const double DefaultTapOpacity = 0.30;
	
	/* Events */
	public Action ButtonDown { get; set; }
	public Action ButtonTapped { get; set; }
	public Action ButtonPressed { get; set; }
	
	/* Properties */

	// Local SVG file
	public string Resource { get => icon.Source?.ToString(); set => icon.Source = value; }
	
	// Colors
	public Color ButtonColor { set => Color = value; }
	public Color IconColor { get => iconColor; set { iconColor = value; UpdateIconColor( value ); } }

	// Tap state
	public double TapOpacity { get; set; }
	
	// Icon sizing
	public double IconScale { get; set; }
	public double Size { set => SetSize( value ); }

	// Draw drop shadow?
	public bool HasShadow { get; set; }

	// Stays in down state until reset?
	public bool IsSticky { get; set; }
	
	// Currently enabled?
	public bool IsDisabled { get => !IsEnabled; set => UpdateDisabled( value ); }

	// Tests if button configured
	public bool HasResource => !string.IsNullOrWhiteSpace( Resource );

	/* Inherited */
	
	// CornerRadius
	// BorderWidth
	// BorderColor

	/* Fields */
	private Color iconColor;
	
	// Underlying image
	private readonly DXIcon icon;
	
	/* Methods */
	public DXIconButton()
	{
		Padding = DefaultPad;

		Horizontal = LayoutOptions.Fill;
		Vertical = LayoutOptions.Fill;
		
		// Underlying image
		icon = new DXIcon
		{
			Aspect = Aspect.AspectFit,

			// Support transparency
			BackgroundColor = DXColors.Transparent,
			IsOpaque = false,
			
			Horizontal = LayoutOptions.Center,
			Vertical = LayoutOptions.Center
		};

		Content = icon;

		// Default no shadow, no border
		HasShadow = false;
		Elevation = 0;
		
		BorderWidth = 0;
		BorderColor = null;
		
		// Defaults
		IconScale = 1.0;
		IsSticky = false;
		TapOpacity = DefaultTapOpacity;
		
		// Register for events
		Down += OnDown;
		Tapped += OnTapped;
		LongPressing += OnLongPressed;		// Do NOT wait for press release
		
		// WORKAROUND: Required on Android to remove border
		if ( DXDevice.IsAndroid )
		{
			Init();
		}
	}
	
	// Post construction initialization
	public sealed override void Init()
	{
		base.Init();

		// Init styling
		Reset();
	}
	
	// Determines if specified point within bounds of this button
	public bool Contains( Point point )
	{
		return Bounds.Contains( point );
	}
	
	// Convenience method for setting size
	public override void SetSize( double size, bool circle = false )
	{
		base.SetSize( size, circle );
		
		UpdateIconSize( size );
	}
	
	// Updates visual disabled state (based on opacity)
	private void UpdateDisabled( bool disabled )
	{
		IsEnabled = !disabled;
		
		Opacity = disabled ? DisabledOpacity : 1.0;

		if ( HasShadow )
		{
			Shadow = disabled ? EmptyShadow : DefaultShadow;
		}
	}
	
	// Displays button in tapped state
	public void ShowTap()
	{
		Opacity = TapOpacity;

		// Shadow
		if ( HasShadow )
		{
			Shadow = EmptyShadow;
		}
	}

	// Resets button to normal, non-tap state
	public void Reset()
	{
		Opacity = 1.0;
		
		// Shadow
		if ( HasShadow )
		{
			Shadow = DefaultShadow;
		}
	}
	
	// Updates foreground icon color
	private void UpdateIconColor( Color color )
	{
		icon.Behaviors.Clear();
		
		IconTintColorBehavior behavior = new IconTintColorBehavior
		{
			TintColor = color
		};
		
		icon.Behaviors.Add( behavior );
	}

	// Update current icon size
	private void UpdateIconSize( double size )
	{
		double request = (size * IconScale);
		
		// Downscale slightly to fit shape
		icon.WidthRequest = request;
		icon.HeightRequest = request;
	}
	
	/* Event Callbacks */
	
	// User started tap, shows tap state
	private void OnDown( object sender, MR.Gestures.DownUpEventArgs args )
	{
		if ( !IsDisabled )
		{
			ShowTap();
			
			ButtonDown?.Invoke();
		}
	}

	// User completed tap, returns to normal unless sticky
	private void OnTapped( object sender, MR.Gestures.TapEventArgs args )
	{
		if ( !IsDisabled )
		{
			if ( !IsSticky )
			{
				Reset();
			}
		
			ButtonTapped?.Invoke();
		}
	}

	// User long pressed button, callback listener
	private void OnLongPressed( object sender, MR.Gestures.LongPressEventArgs args )
	{
		if ( !IsDisabled )
		{
			ButtonPressed?.Invoke();
		}
	}
}

//
