/* 
 * 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.Card;
using DXLib.UI.Layout;
using DXLib.UI.Control;
using DXLib.UI.Container;

using DXLib.Utils;

namespace iStatVball3;

/*
 * Displays full list of dashboard cards for the Analyze dashboard screen. An 'Add New' card is also displayed for
 * creating custom dashboards.
 */
public class DashboardLayout : DXScroll
{
	/* Constants */
	private const double BasePadding = 15;

	/* Events */
	public Action<JsonCategory> CardTapped { get; set; }

	/* Properties */
	public DashboardConfig Config { get; set; }
	public CustomConfig CustomConfig { get; set; }

	/* Fields */
	private readonly DXGridLayout layout;
	private readonly List<DXCard> cards;

	private DXCardNew newCard;

	// Permissions
	private bool hasAccess;

	/* Methods */
	public DashboardLayout()
	{
		BackgroundColor = DXColors.Dark1;

		// Layout
		layout = new DXGridLayout
		{
			RowSpacing = BasePadding,
			ColumnSpacing = BasePadding,
			
			Horizontal = LayoutOptions.Fill,
			Vertical = LayoutOptions.Fill,
			
			// Do NOT ignore
			IgnoreSafeArea = false
		};

		Content = layout;

		// Underlying data structure
		cards = [];
	}

	// Create all cards from JSON configuration
	public void Init( string scope )
	{
		JsonAnalyze json = DashboardCache.Instance.Json;

		// Current user has access to all categories?
		hasAccess = Config.IsSample || HasAccess();

		cards.Clear();

		// Add categories for each group
		foreach ( JsonGroup group in json.Groups )
		{
			// Add card for each category
			foreach ( JsonCategory category in group.GetCategories() )
			{
				// Some categories might be excluded
				if ( IsValid( category ) && IsInScope( category, scope ) )
				{
					DashboardCard card = new( category.Custom )
					{
						Data = category,
						CustomConfig = CustomConfig,

						Icon = $"category_{group.Title.ToLower()}",
						Category = category.Title,
						Group = group.Title,

						CardTapped = OnCardTapped
					};

					card.Init();

					// Add name/value for each metric
					foreach ( JsonMetric metric in category.Metrics )
					{
						card.AddMetric( metric );
					}

					cards.Add( card );
				}
			}
		}

		// 'Add New' card for custom dashboards
		if ( CustomDashboard.CanCreate( Shell.CurrentUser, Config.Organization ) )
		{
			AddNewCard();
		}
	}

	// Adds 'Add New' card to card list
	private void AddNewCard()
	{
		// Create card
		newCard = new DXCardNew
		{
			Type = "dashboard",
			CardHt = DashboardCard.CardHt,
			CardTapped = OnNewCardTapped
		};

		newCard.Init();
		
		// Always at end
		cards.Add( newCard );
	}

	// Determines if specified category valid to display
	private bool IsValid( JsonCategory category )
	{
		CustomDashboard custom = category.Custom;
		bool hasCustom = (custom != null );

		// Default to Team 1
		bool team1 = CustomConfig.IsTeam1;
		bool team1Dashboard = hasCustom ? custom.IsTeam1 : team1;

		// Some categories not valid for all access levels
		bool permissionValid = category.Open || hasAccess;

		// Some categories not valid for opponent
		bool opponentValid = team1 || category.Opponent;

		// Must be showing correct dashboard
		bool teamValid = (team1 && team1Dashboard) || (!team1 && !team1Dashboard);

		// Some categories not valid for media or opponent
		return !category.Hidden && (permissionValid && opponentValid && teamValid);
	}

	// Determines if specified scope supported by dashboard category
	private static bool IsInScope( JsonCategory category, string scope )
	{
		IList<string> include = category.Include;

		// Check against include list
		if ( include != null )
		{
			return include.Contains( scope );
		}

		IList<string> exclude = category.Exclude;

		// Check against exclude list
		if ( exclude != null )
		{
			return !exclude.Contains( scope );
		}

		// Everything else included
		return true;
	}

	// Removes all cards from page
	public void Clear()
	{
		cards.Clear();
	}

	// Resets tap state for all cards on dashboard
	public void Reset()
	{
		foreach ( DXCard card in cards )
		{
			card.Reset();
		}

		newCard?.Reset();
	}

	// Updates values for all metrics on all cards in all categories
	public void UpdateData()
	{
		foreach ( DXCard card in cards )
		{
			if ( card is DashboardCard dashboardCard )
			{
				dashboardCard.UpdateData();
			}
		}

		DXSpinner.Stop();
	}

	/* Permissions */

	// Determines if current user has access to all categories
	private static bool HasAccess()
	{
		User user = Shell.CurrentUser;

		return user.Level switch
		{
			// Media does not
			User.LevelType.Media => false,
			
			// Stat only if linked to player
			User.LevelType.Statistician => user.HasPermission(),
			
			// Everyone else does
			_ => true
		};
	}

	/* Event Callbacks */

	// Dashboard card was tapped
	private void OnCardTapped( DXCard card )
	{
		if ( card is DashboardCard dashboardCard )
		{
			JsonCategory category = dashboardCard.Data as JsonCategory;

			CardTapped?.Invoke( category );
		}
	}

	// User tapped 'Add New' card
	private void OnNewCardTapped( DXCard card )
	{
		// Create edit form
		CustomForm form = new( null )
		{
			Config = CustomConfig
		};
		
		form.Init();
		
		// Open in create mode
		Shell.Instance.ShowForm( form );
	}

	/* Layout */

	// Device/orientation specific layout
	public override void UpdateLayout( LayoutType type )
	{
		bool mobileLand = (type == LayoutType.MobileLandscape);
		
		// REQUIRED to be dynamic
		layout.IgnoreSafeArea = !mobileLand;

		double leftPad = mobileLand ? (BasePadding * 2) : BasePadding;
		double bottomPad = DXDevice.IsIOS ? 0 : BasePadding;
		
		Thickness basePadding = new( leftPad, BasePadding, BasePadding, bottomPad );

		// Account for mobile notch
		Padding = DXUtils.AddPadding( basePadding, DXDevice.SafeAreaLR() );

		// Number columns depends on device type/orientation
		switch ( type )
		{
			case LayoutType.Landscape: case LayoutType.WideLandscape: UpdateGrid( 3 ); break;
			case LayoutType.Portrait: case LayoutType.WidePortrait: UpdateGrid( 2 ); break;
			case LayoutType.MobileLandscape: UpdateGrid( 2 ); break;
			case LayoutType.MobilePortrait: UpdateGrid( 1 ); break;
			default: break;
		}

		// Update child cards
		foreach ( DXCard card in cards )
		{
			card.UpdateLayout( type );
		}
	}

	// Lays out grid based on screen size
	private void UpdateGrid( int colCount )
	{
		layout.ClearAll();

		int count = cards.Count;

		// List may be empty
		if ( count > 0 )
		{
			int rowCount = (count / colCount);

			// May be partial row
			if ( (count % colCount) != 0 )
			{
				rowCount++;
			}

			// Add rows, all same height
			for ( int row = 0; row < rowCount; row++ )
			{
				layout.AddFixedRow( DashboardCard.CardHt );
			}

			// Add columns, all same width
			for ( int col = 0; col < colCount; col++ )
			{
				layout.AddStarColumn();
			}

			// Populate grid
			for ( int row = 0; row < rowCount; row++ )
			{
				for ( int col = 0; col < colCount; col++ )
				{
					int index = (row * colCount) + col;

					if ( index < count )
					{
						layout.Add( cards[ index ], col, row );
					}
				}
			}
		}
	}
}

//
