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

using System.Globalization;
using Syncfusion.Maui.Buttons;

using DXLib.UI.Layout;
using DXLib.Utils;

namespace DXLib.UI.Control;

/*
 * A segment bar control with a variable length, horizontal list of icon and/or text items. A border outline indicates
 * the currently selected item.
 */
public class DXSegmentBar : SfSegmentedControl
{
	/* Constants */
	public const double SelectionWd = 3;
	private const double IconSize = 40;
	
	// Available segment types
	public enum SegmentMode
	{
		Text,
		IconText
	};

	/* Events */
	public Action<string> Selected { get; set; }

	/* Properties */
	public LayoutOptions Horizontal { set => HorizontalOptions = value; }
	public LayoutOptions Vertical { set => VerticalOptions = value; }

	// Icon and text, or text only?
	public SegmentMode Mode { get => segmentMode; set => SetMode( value ); }
	public bool IsIconText => Mode == SegmentMode.IconText;

	// Colors
	public Color FillColor { get; set; }
	public Color TextColor { get; set; }
	public Color IconColor { get; set; }
	public Color SelectColor { get; set; }

	// Custom sizing
	public double SegmentWd { set => SegmentWidth = value; }
	public double SegmentHt { set => SetHt( value ); }

	// Custom font
	public string SegmentFont { get; set; }
	public double SegmentFontSize { get; set; }

    // Currently selected item
    public string SelectedKey { get => GetSelectedKey(); set => SelectKey( value ); }

	// Maximum text length to display
	public int MaxTextLen { get; set; }

	/* Fields */
	private SegmentMode segmentMode;
	
	private readonly List<string> keys;
	private readonly List<SfSegmentItem> segments;

	/* Methods */
	public DXSegmentBar()
	{
		// Allocate containers
		keys = [];
		segments = [];

		ItemsSource = segments;

		// Defaults
		MaxTextLen = 17;

		// Register for events
		SelectionChanged += OnSelectionChanged;
	}

	// Post-construction initialization
	public void Init()
	{
		// Selected segment
		SelectionIndicatorSettings selectionIndicator = new()
		{
			SelectionIndicatorPlacement = SelectionIndicatorPlacement.Border,
			TextColor = SelectColor,
			
			Stroke = SelectColor,
			StrokeThickness = SelectionWd
		};
		
		// Bar config
		SegmentBackground = FillColor;
		DisabledSegmentTextColor = DXColors.Dark4;
		DisabledSegmentBackground = FillColor; 
		
		SegmentFont = DXFonts.RobotoBoldItalic;
		ShowSeparator = true;

		UpdateStyle();

		StrokeThickness = 0;
		CornerRadius = 5;
		SegmentCornerRadius = 5;

		SelectionIndicatorSettings = selectionIndicator;
	}

	// Forces update of segment bar text style
	public void UpdateStyle()
	{
        TextStyle = new SegmentTextStyle
        {
            TextColor = TextColor,

            FontFamily = DXFonts.RobotoBoldItalic,
            FontSize = SegmentFontSize,
            FontAttributes = FontAttributes.None
        };
    }

    // Used internally to set icon or icon/text display modes
    private void SetMode( SegmentMode mode )
	{
		segmentMode = mode;

		// Custom template for vertically stacked icon/text
		if ( segmentMode == SegmentMode.IconText )
		{
			SegmentTemplate = new DataTemplate( GetIconTextLayout );
		}
	}

	// Creates custom layout for icon/text mode
	private DXGridLayout GetIconTextLayout()
	{
		EnabledConverter converter = new();
		
		// Layout
		DXGridLayout layout = new()
		{
			Padding = new Thickness( 0, 3, 0, 3 ),
			Margin = 0,
			RowSpacing = 0,
			
			Horizontal = LayoutOptions.Fill,
			Vertical = LayoutOptions.Fill
		};

		// Icon
		DXIcon icon = new()
		{
			Color = IconColor,
			
			Horizontal = LayoutOptions.Center,
			Vertical = LayoutOptions.End
		};

		icon.SetSize( IconSize );
		
		icon.SetBinding( Microsoft.Maui.Controls.Image.SourceProperty, "ImageSource" );
		icon.SetBinding( OpacityProperty, new Binding( "IsEnabled", converter:converter ) );

		// Text
		DXLabel label = new()
		{
			Font = DXFonts.RobotoBoldItalic,
			FontSize = SegmentFontSize,
			TextColor = TextColor,
			
			Padding = 0,
			Margin = 0,
			
			Horizontal = LayoutOptions.Center,
			Vertical = LayoutOptions.Start
		};

		label.SetBinding( Label.TextProperty, "Text" );
		label.SetBinding( OpacityProperty, new Binding( "IsEnabled", converter:converter ) );
		
		layout.AddFixedRow( IconSize );
		layout.AddStarRow();
		
		layout.Add( icon, 0, 0 );
		layout.Add( label, 0, 1 );

		return layout;
	}
	
	/* Add */

	// Creates a text-only segment from resource text
	public void AddSegment( string key, string resource = null )
	{
		keys.Add( key );

		segments.Add( new SfSegmentItem
		{
			Text = (resource == null) ? string.Empty : DXString.GetUpper( resource )
		});
	}

	// Creates a text-only segment from raw text
	public void AddSegmentText( string key, string text = null )
	{
		keys.Add( key );

		segments.Add( new SfSegmentItem
		{
			Text = (text == null) ? string.Empty : GetText( text )
		});
	}

	// Creates an icon/text segment with specified icon and resource text
	public void AddSegmentIconText( string key, string icon, string resource )
	{
		keys.Add( key );

		segments.Add( new SfSegmentItem
		{
			ImageSource = icon,
			Text = DXString.Get( resource )
		});
	}

	/* Get/Set */

	// Returns canonical copy of specified text
	private string GetText( string text )
	{
		return text?[ ..Math.Min( text.Length, MaxTextLen ) ];
	}

	// Dynamically sets text value with given resource
	public void SetResource( string key, string resource )
	{
		SetText( key, DXString.GetUpper( resource ) );
	}

	// Dynamically sets text value for specified segment
	public void SetText( string key, string text )
	{
		int index = GetIndex( key );

		segments[ index ].Text = GetText( text );
	}

	/* Select */

	// Returns unique key of currently selected segment
	private string GetSelectedKey()
	{
		return (SelectedIndex >= 0) ? keys[ (int)SelectedIndex ] : null;
	}

	// Selects segment corresponding to specified unique key
	public void SelectKey( string key )
	{
		SelectedIndex = GetIndex( key );
	}

	// Prevents event callback on internal programmatic selection (Syncfusion code)
	private bool IsSelectValid()
	{
		return Children is { Count: > 0 } && (Children[0].DesiredSize.Width > 0) && (DesiredSize.Height > 0);
	}
	
	// Returns index of specified unique key
	private int GetIndex( string key )
	{
		for ( int index = 0; index < keys.Count; index++ )
		{
			// Match found
			if ( keys[ index ] == key )
			{
				return index;
			}
		}

		// No match
		return -1;
	}

	/* Disable */

	// Disables all control segments
	public void DisableAll( bool disabled = true )
	{
		foreach ( SfSegmentItem segment in segments )
		{
			segment.IsEnabled = !disabled;
		}
	}

	// Visually disables specified segment
	public void Disable( string key, bool disabled )
	{
		int index = GetIndex( key );

		segments[ index ].IsEnabled = !disabled;
	}

	/* Sizing */

	// Dynamically sets bar height
	private void SetHt( double ht )
	{
		SegmentHeight = (ht == 0) ? (IsIconText ? 55 : 40) : ht;
	}

	// Determines if specified point in bar bounds
	public bool Contains( Point pt )
	{
		return Bounds.Contains( pt );
	}

	/* Event Callback */

	// Handles selection change, calls back registered listener
	private void OnSelectionChanged( object sender, Syncfusion.Maui.Buttons.SelectionChangedEventArgs args )
	{
		// Do NOT callback listener on programmatic selection
		if ( IsSelectValid() )
		{
			int index = (int) args.NewIndex!;

			if ( segments[ index ].IsEnabled )
			{
				Selected?.Invoke( keys[ index ] );
			}
		}
	}
}

/*
 * Handles reduced opacity for disabled segments.
 */
public class EnabledConverter : IValueConverter
{
	/* Methods */
	
	// Returns opacity based on enabled state
	public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
	{
		return ((bool)value!) ? 1.0 : 0.3;
	}

	// NA
	public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
	{
		throw new NotImplementedException();
	}
}

//
