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

using Syncfusion.Maui.Popup;

using DXLib.UI.Layout;
using DXLib.UI.Container;

using DXLib.UI.Control;
using DXLib.UI.Control.Button;

using DXLib.Utils;

namespace DXLib.UI.Alert;

/*
 * Displays a modal popup with either OK, OK/Cancel, or custom Destroy/Cancel buttons. Title and message strings are
 * read from the external resource file. A callback event handler must be specified for the OK/Destroy button. Be default,
 * the cancel button dismisses the alert with no callback action.
 */
public static class DXAlert
{
	/* Constants */
	public static readonly Color OverlayColor = Color.FromArgb( "#99000000" );
	
	/* Fields */
	private static SfPopup popup;

	private static DXLabel headerLbl;
	private static DXLabel msgLbl;

	// Footers
	private static DXGridLayout okCancelFooter;

	// Buttons
	private static DXButton cancelBtn;
	private static DXButton actionBtn;

	// Callbacks
	private static Action cancelAction;
	private static Action okAction;

	/* Methods */

	// Post construction initialization
	private static void Init()
	{
		bool tablet = DXDevice.IsTablet;
		
		// Fixed size
		double wd = tablet ? 360 : 340;

		const int headerHt = 40;
		const int bodyHt = 125;
		const int footerHt = 50;

		popup.HeaderHeight = headerHt;
		popup.FooterHeight = footerHt;
		popup.AutoSizeMode = PopupAutoSizeMode.Both;
		
		popup.Padding = 0;
		popup.Margin = 0;

		// Modal
		popup.StaysOpen = true;
		popup.IsFullScreen = false;

		// Header/footer
		popup.ShowHeader = true;
		popup.ShowFooter = true;
		popup.ShowCloseButton = false;

		// Quick fade animation in/out
		popup.AnimationMode = PopupAnimationMode.Fade;
		popup.AnimationEasing = PopupAnimationEasing.SinIn;
		popup.AnimationDuration = 250;		
		
		PopupStyle style = popup.PopupStyle;

		// Style
		style.CornerRadius = 4;
		style.HasShadow = true;
		style.OverlayColor = OverlayColor;
		style.PopupBackground = DXColors.Light4;

		style.StrokeThickness = 1;
		style.Stroke = DXColors.Dark3;

		popup.BackgroundColor = DXColors.Light4;
		
		// Header
		DXContent headerView = new()
		{
			Padding = new Thickness( 17, 5, 15, 0 ),
			Margin = 0,
			
			BackgroundColor = DXColors.Light4,
			
			WidthRequest = wd,
			HeightRequest = headerHt
		};

		headerLbl = new DXLabel
		{
			Padding = 0,
			Margin = 0,
			
			TextColor = DXColors.Dark1,
			Font = DXFonts.RobotoBold,
			FontSize = 20,

			LineBreakMode = LineBreakMode.NoWrap,
			VAlign = TextAlignment.Center,

			Horizontal = LayoutOptions.Start,
			Vertical = LayoutOptions.Center
		};

		headerView.Content = headerLbl;

		popup.HeaderTemplate = new DataTemplate( () => headerView);

		// Body
		DXContent contentView = new()
		{
			Padding = new Thickness( 17, 0, 15, 15 ),
			Margin = 0,
			
			BackgroundColor = DXColors.Light4,
			Vertical = LayoutOptions.Start,

			WidthRequest = wd,
			HeightRequest = bodyHt
		};

		msgLbl = new DXLabel
		{
			Padding = new Thickness( 0, 10, 0, 0 ),
			Margin = 0,
			
			Font = DXFonts.Roboto,
			FontSize = 17,
			
			TextColor = DXColors.Dark1,
			LineBreakMode = LineBreakMode.WordWrap
		};

		contentView.Content = msgLbl;

		popup.ContentTemplate = new DataTemplate( () => contentView );

		/* OK/Cancel */

		// Footer
		okCancelFooter = new DXGridLayout
		{
			Padding = new Thickness( 0, 0, 0, 10 ),
			Margin = 0,
			
			ColumnSpacing = 10,
			BackgroundColor = DXColors.Light4,
			
			WidthRequest = wd,
			HeightRequest = footerHt
		};

		okCancelFooter.AddStarColumn();
		okCancelFooter.AddAutoColumn();
		okCancelFooter.AddFixedColumn( 5 );

		// Cancel
		cancelBtn = new DXButton
		{
			Resource = "alert.cancel",
			Type = DXButton.ButtonType.Neutral,

			ButtonWd = 80,

			Horizontal = LayoutOptions.End,
			Vertical = LayoutOptions.Center
		};

		cancelBtn.Init();
		
		// OK
		actionBtn = new DXButton
		{
			Horizontal = LayoutOptions.End,
			Vertical = LayoutOptions.Center
		};

		actionBtn.Init();
		
		okCancelFooter.Add( cancelBtn, 0, 0 );
		okCancelFooter.Add( actionBtn, 1, 0 );

		// Register for events
		cancelBtn.ButtonTapped += OnCancelTapped;
		actionBtn.ButtonTapped += OnActionTapped;
	}

	// Removes any open alert
	public static void Hide()
	{
		popup?.IsOpen = false;			// Do NOT use Dismiss()
	}

	/* OK */

	// Shows alert with positive OK button
	public static void ShowOk( string title, string msg, Action action = null )
	{
		ShowOkRaw( DXString.Get( title ), DXString.Get( msg ), action );
	}

	// Shows alert with positive OK button and optional merged text
	public static void ShowOk( string title, string msg, string msgInsert, Action action = null )
	{
		ShowOkRaw( DXString.Get( title ), DXString.Get( msg, msgInsert ), action );
	}

	// Shows positive OK alert with raw title/msg strings
	public static void ShowOkRaw( string title, string msg, Action action = null )
	{
		Build( title, msg, action );

		cancelBtn.IsVisible = false;

		// OK
		actionBtn.Resource = "alert.ok";
		actionBtn.Type = DXButton.ButtonType.Positive;

		popup.Show();
	}

	/* Neutral */
	
	// Shows alert with neutral OK button
	public static void ShowNeutral( string title, string msg, Action action = null )
	{
		ShowNeutral( title, msg, null, action );
	}

	// Shows alert with neutral OK button and optional insert text
	public static void ShowNeutral( string title, string msg, string msgInsert, Action action = null )
	{
		ShowNeutralRaw( DXString.Get( title ), DXString.Get( msg, msgInsert ), action );
	}
	
	// Shows alert with neutral OK button and raw title/msg strings
	public static void ShowNeutralRaw( string title, string msg, Action action = null )
	{
		Build( title, msg, action );

		cancelBtn.IsVisible = false;

		// OK
		actionBtn.Resource = "alert.ok";
		actionBtn.Type = DXButton.ButtonType.Neutral;

		popup.Show();
	}

	/* OK-Cancel */

	// Shows alert with positive OK button and Cancel button
	public static void ShowOkCancel( string title, string msg, Action action, Action cancel = null )
	{
		ShowOkCancel( title, msg, null, action, cancel );
	}

	// Shows alert with positive OK button, optional merged text, and Cancel button
	public static void ShowOkCancel( string title, string msg, string msgInsert, Action action, Action cancel = null )
	{
		ShowOkCancelRaw( DXString.Get( title ), DXString.Get( msg, msgInsert ), action, cancel );
	}

	// Shows alert with positive OK button, cancel button, and raw title/msg strings
	public static void ShowOkCancelRaw( string title, string msg, Action action, Action cancel = null )
	{
		Build( title, msg, action, cancel );

		cancelBtn.IsVisible = true;

		// OK
		actionBtn.Resource = "alert.ok";
		actionBtn.Type = DXButton.ButtonType.Positive;

		popup.Show();
	}
	
	/* Positive-Cancel */
	
	// Shows alert with custom positive button with Cancel button
	public static void ShowPositiveCancel( string title, string msg, string create, Action action, Action cancel = null )
	{
		ShowPositiveCancelRaw( DXString.Get( title ), DXString.Get( msg ), create, action, cancel );
	}

	// Shows alert with custom positive button with Cancel button
	public static void ShowPositiveCancelRaw( string title, string msg, string create, Action action, Action cancel = null )
	{
		Build( title, msg, action, cancel );

		cancelBtn.IsVisible = true;

		// Custom Cancel
		cancelBtn.Resource = "alert.cancel";
		cancelBtn.Type = DXButton.ButtonType.Neutral;

		// Custom OK
		actionBtn.Resource = create;
		actionBtn.Type = DXButton.ButtonType.Positive;

		actionBtn.ButtonWd = 85;

		popup.Show();
	}

	/* Negative-Cancel */
	
	// Shows alert with custom destructive button with Cancel button
	public static void ShowNegativeCancel( string title, string msg, string destroy, Action action, Action action2 = null )
	{
		ShowNegativeCancelRaw( DXString.Get( title ), DXString.Get( msg ), destroy, action, action2 );
	}

	// Shows alert with custom destructive button and optional dynamic text
	public static void ShowNegativeCancel( string title, string titleInsert, string msg, string msgInsert, string destroy, Action action )
	{
		ShowNegativeCancelRaw( DXString.Get( title, titleInsert ), DXString.Get( msg, msgInsert ), destroy, action );
	}

	// Shows alert with custom destructive button with Cancel button
	public static void ShowNegativeCancelRaw( string title, string msg, string destroy, Action action, Action action2 = null )
	{
		Build( title, msg, action, action2 );

		cancelBtn.IsVisible = true;

		// Custom destroy
		actionBtn.Resource = destroy;
		actionBtn.Type = DXButton.ButtonType.Negative;

		actionBtn.ButtonWd = 86;

		popup.Show();
	}

	/* Error */

	// Shows alert with 'Error' title and neutral OK button
	public static void ShowError( string msg, Action action = null )
	{
		ShowError( null, msg, null, null, null, action );
	}

	// Shows alert with 'Error' title, optional merged text, and neutral OK button
	public static void ShowError( string titleInsert, string msg, Action action )
	{
		ShowError( titleInsert, msg, null, null, null, action );
	}

	// Shows alert with 'Error' title, optional merged text, and neutral OK button
	public static void ShowError( string titleInsert, string msg, string msgInsert, Action action )
	{
		ShowError( titleInsert, msg, msgInsert, null, null, action );
	}

	// Shows alert with 'Error' title, optional merged text, optional error code, and neutral OK button
	public static void ShowError( string titleInsert, string msg, string msgInsert = null, string msgInsert2 = null, int? code = null, Action action = null )
	{
		string titleStr = (titleInsert == null) ? DXString.Get( "alert.error" ) : DXString.Get( "alert.error.prefix", DXString.Get( titleInsert ) );
		string msgStr = DXString.Get( msg, msgInsert, msgInsert2 );

		// Optionally append error code
		if ( code is not null )
		{
			msgStr += $" ({code})";
		}
		
		ShowErrorRaw( titleStr, msgStr, action );
	}

	// Shows error alert with raw title/msg strings and optional event callback
	public static void ShowErrorRaw( string title, string msg, Action action = null )
	{
		Build( title, msg, action );

		cancelBtn.IsVisible = false;

		// OK
		actionBtn.Resource = "alert.ok";
		actionBtn.Type = DXButton.ButtonType.Neutral;

		popup.Show();
	}
	
	/* Error Code */

	// Shows error alert with appended error code
	public static void ShowErrorCode( string titleInsert, string msg, int code )
	{
		ShowErrorCode( titleInsert, msg, code, null );
	}

	// Shows error alert with appended error code
	public static void ShowErrorCode( string titleInsert, string msg, int code, Action action )
	{
		ShowError( titleInsert, msg, null, null, code, action );
	}

	/* Network */

	// Shows alert with 'Network Error' title and neutral OK button
	public static void ShowNetworkError( string msg, Action action = null )
	{
		ShowNetworkError( msg, null, action );
	}

	// Shows alert with 'Network Error' title and neutral OK button
	public static void ShowNetworkError( string msg, string msgInsert, Action action = null )
	{
		ShowNeutral( "net.err.req", "net.err.base", DXString.Get( msg, msgInsert ), action );
	}

	/* Destroy */
	
	// Shows alert with negative destroy button and neutral action
	public static void ShowDestroy( string title, string msg, string destroy, string action, Action destroyAction, Action actionAction )
	{
		ShowDestroyRaw( title, msg, DXString.Get( destroy ), DXString.Get( action ), destroyAction, actionAction );
	}
	
	// Shows alert raw destroy/action and title/msg strings
	public static void ShowDestroyRaw( string title, string msg, string destroy, string action, Action destroyAction, Action actionAction )
	{
		Build( title, msg, actionAction, destroyAction );

		// Cancel used as destroy
		cancelBtn.Text = destroy;
		cancelBtn.Type = DXButton.ButtonType.Negative;

		cancelBtn.ButtonWd = 86;
		cancelBtn.IsVisible = true;

		// Custom action
		actionBtn.Text = action;
		actionBtn.Type = DXButton.ButtonType.Neutral;

		actionBtn.ButtonWd = 86;

		popup.Show();
	}

	/* Build */

	// Builds all alert types using raw strings
	private static void Build( string title, string msg, Action action, Action cancel = null )
	{
		// Create popup
		popup = new SfPopup();
		
		// Initialize
		Init();

		// Set title
		headerLbl.Text = title;

		// Set message
		msgLbl.Text = msg;

		// Save callbacks
		okAction = action;
		cancelAction = cancel;

		// Set buttons
		popup.FooterTemplate = new DataTemplate( () => okCancelFooter);
	}

	/* Event Callbacks */

	// Cancel tapped
	private static void OnCancelTapped( object sender )
	{
		Hide();

		cancelAction?.Invoke();
	}

	// OK or Destroy tapped
	private static void OnActionTapped( object sender )
	{
		Hide();
		
		okAction?.Invoke();
	}
}

//
