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

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

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

using DXLib.Data;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Interface for choosing a dimension and filters for the Report Builder. The dimension can be either outer or inner level.
 */
public class BuilderDimension : DXGridLayout
{
	/* Constants */

	// Sizing
	private const double IconHt = 30;
	private static readonly Thickness BasePadding = new( 15, 5, 10, 5 );

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

	/* Properties */
	public string SelectedKey { get => GetSelectedKey(); set => SetSelectedKey( value ); }

	// Filter
	public bool HasFilter { get => filterBtn.IsVisible; set => filterBtn.IsVisible = value; }
	public List<object> Filter => filter.GetFilter();

	// Allow team-only selection?
	public bool AllowEmpty { get => filter.AllowEmpty; set => filter.AllowEmpty = value; }

	/* Fields */
	private readonly DXLabel titleLbl;
	private readonly DXSelector selector;
	private readonly DXIconButton filterBtn;
	private readonly DXLabel filterLbl;

	// Filter popup
	private readonly BuilderFilter filter;
	private DXPopup popup;

	// Outer/inner
	private readonly DataDimension.Level level;

	// Programmatic/user selection?
	private bool internalSelect;

	/* Methods */
	public BuilderDimension( DataDimension.Level level )
	{
		this.level = level;

		bool ios = DXDevice.IsIOS;

		BackgroundColor = DXColors.Light2;

		RowSpacing = ios ? 4 : 0;
		ColumnSpacing = 15;

		Horizontal = LayoutOptions.Fill;
		Vertical = LayoutOptions.Fill;

		// REQUIRED
		IgnoreSafeArea = true;

		double selectorHt = ios ? 25 : 30;
		double filterHt = ios ? 27 : 22;
		
		// 2 rows
		AddFixedRow( selectorHt );		// 0: title, selector, filter btn
		AddFixedRow( filterHt );		// 1: filter list

		// 2 columns
		AddAutoColumn();				// 0: title
		AddStarColumn();				// 1: selector, filter list
		AddFixedColumn( IconHt );		// 2: filter btn

		bool outer = (level == DataDimension.Level.Outer);
		Color color = DXColors.Dark3;

		// Title
		titleLbl = new DXLabel
		{
			Resource = outer ? "builder.by" : "builder.then",

			TextColor = color,
			Font = DXFonts.RobotoBold,
			FontSize = 17,

			Vertical = LayoutOptions.Center
		};

		Add( titleLbl, 0, 0 );

		// Dimension combobox
		selector = new DXSelector
		{
			BackgroundColor = DXColors.Light2,
			
			Margin = new Thickness( 0, (ios ? -3 : 0), 0, 0 ),
			Padding = 0,
			
			Selected = OnDimensionSelected
		};

		Add( selector, 1, 0 );

		// Filter
		filterBtn = new DXIconButton
		{
			Resource = "filter",
			IconColor = color,
			Size = IconHt,

			Horizontal = LayoutOptions.End,
			Vertical = LayoutOptions.Start,
			
			Padding = 0,
			Margin = 0,

			IsSticky = true,
			ButtonTapped = OnFilterTapped
		};

		Add( filterBtn, 2, 0, 1, 2 );

		// Filter data control
		filter = new BuilderFilter( level )
		{
			Selected = OnFilterSelected
		};

		// Filter list
		filterLbl = new DXLabel
		{
			TextColor = DXColors.Dark3,
			Font = DXFonts.Roboto,
			FontSize = 14,

			LineBreakMode = LineBreakMode.TailTruncation,
			Margin = new Thickness( (ios ? 7 : 2), 0, 0, 0 )
		};

		Add( filterLbl, 1, 1 );
	}

	// Loads all dimension entries for specified team (with optional filter)
	public void Load( bool isTeam1, List<string> keys, string filterKey = null )
	{
		List<DXItem> items = new( keys.Count );

		// Inner dimension always has NA pre-pended
		if ( level == DataDimension.Level.Inner )
		{
			DXItem item = new()
			{
				Key = KeyDimension.NoneKey,
				Value = KeyDimension.NoneTitle
			};

			items.Add( item );
		}

		// Add all relevant dimensions
		foreach ( string key in keys )
		{
			// Some dimensions not applicable to Team 2
			if ( KeyDimension.Include( key, isTeam1 ) )
			{
				// Can optionally filter outer dimension from inner list
				if ( (filterKey == null) || (key != filterKey) )
				{
					DXItem item = new()
					{
						Key = key,
						Value = KeyDimension.GetTitle( key )
					};

					items.Add( item );
				}
			}
		}

		// Populate underlying control
		selector.LoadItems( items );

		// Disable if empty
		Disable( items.Count == 0 );
	}

	// Sets default dimension based on currently selected team
	public void SelectDefault( bool isTeam1 )
	{
		internalSelect = true;

		// Inner dimension always starts NA
		if ( level == DataDimension.Level.Inner )
		{
			SelectedKey = KeyDimension.NoneKey;
		}
		else
		{
			// Outer Team 1 defaults to Player (unless not applicable)
			if ( isTeam1 )
			{
				bool hasPlayer = selector.HasKey( KeyDimension.PlayerKey );

				SelectedKey = hasPlayer ? KeyDimension.PlayerKey : KeyDimension.RotationKey;
			}
			// Outer Team 2 always defaults to Rotation
			else
			{
				SelectedKey = KeyDimension.RotationKey;
			}
		}

		// 'All Players/Rotations'
		UpdateFilterAll( SelectedKey );

		internalSelect = false;
	}

	// Returns currently selected item key, null if NA
	private string GetSelectedKey()
	{
		string key = selector.SelectedKey;

		return key is null or KeyDimension.NoneKey ? null : key;
	}

	// Selects item matching specified key
	private void SetSelectedKey( string key )
	{
		internalSelect = true;

		// Do not call back listener
		selector.SelectKey( key );

		internalSelect = false;
	}

	// Visually disables all components
	public void Disable( bool disabled )
	{
		titleLbl.IsDisabled = disabled;
		selector.SetDisabled( disabled );

		filterBtn.IsDisabled = disabled;
		filterLbl.IsVisible = !disabled;
	}

	// Forwards new data to filter
	public void UpdateData( DataConfig config, DataStats stats )
	{
		if ( HasFilter )
		{
			filter.UpdateData( config, stats );
		}
	}

	/* Filter */

	// Displays list of selected filters for current dimension
	private void UpdateFilter( string key )
	{
		if ( HasFilter )
		{
			if ( filter.HasFilter() )
			{
				filterLbl.Text = KeyDimension.GetValues( key, filter.GetFilter() );
			}
			else
			{
				UpdateFilterAll( key );
			}
		}
	}

	// Displays 'All Players/Rotations' when no filters selected
	private void UpdateFilterAll( string key )
	{
		if ( HasFilter )
		{
			filterLbl.Text = KeyDimension.GetAllTitle( key );
		}
	}

	/* Event Callbacks */

	// User changed combobox selection		 
	private void OnDimensionSelected( object item )
	{
		// Do NOT callback listener for internal selections
		if ( !internalSelect )
		{
			string key = (item as DXItem)?.Key;

			DimensionChanged?.Invoke( key );

			// 'All Players/Rotations'
			UpdateFilterAll( key );
		}
	}

	// User tapped filter button
	private void OnFilterTapped()
	{
		// Create popup
		popup = new DXPopup()
		{
			AutoSize = true,
			PopupClosed = OnFilterClosed
		};

		string title = KeyDimension.GetTitle( GetSelectedKey(), true );
		
		popup.SetTitle( title );
		popup.SetContent( filter );
		
		// Show
		popup.ShowFromView( filterBtn );
	}

	// User dismissed popup
	private void OnFilterClosed()
	{
		filterBtn.Reset();
	}

	// User changed filter, notify listener
	private void OnFilterSelected()
	{
		FilterChanged?.Invoke();

		popup.Hide();

		// Show list of selected filters
		UpdateFilter( SelectedKey );
	}
	
	/* Layout */

	// Device/orientation specific layout
	public override void UpdateLayout( LayoutType type )
	{
		base.UpdateLayout( type );

		// Mobile-landscape must account for left/right notch
		if ( type == LayoutType.MobileLandscape )
		{
			Thickness safeArea = DXDevice.SafeArea();

			Padding = level switch
			{
				DataDimension.Level.Outer => DXUtils.AddPadding( BasePadding, new Thickness( safeArea.Left, 0, 0, 0 ) ),
				DataDimension.Level.Inner => DXUtils.AddPadding( BasePadding, new Thickness( 0, 0, safeArea.Right, 0 ) ),
				_ => Padding
			};
		}
		// Otherwise normal padding
		else
		{
			Padding = BasePadding;
		}
	}
}

//
