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

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

using DXLib.Data.Model;

using DXLib.Log;
using DXLib.Utils;

namespace DXLib.UI.Card;

/*
 * A UI page containing a list of DXCard instances arranged in a grid. The number of columns depends on the size of the
 * device. Individual cards are always same height regardless of screen size/layout, only width varies.
 */
public abstract class DXCardPage : DXScroll
{
	/* Constants */
	public const double BasePadding = 15;

	// Current layout
	public int RowCount => layout.RowCount;
	public int ColumnCount => layout.ColumnCount;
	
	/* Properties */

	// Screen title displayed in AppBar
	public string Title { get; protected set; }

	// Page auto-scrolls to top or bottom?
	public ScrollToPosition ScrollPosition { get; set; }

	/* Fields */
	protected readonly object data;

	protected readonly DXGridLayout layout;
	protected readonly List<DXCard> cards;

	private int rowCount;

	/* Methods */
	protected DXCardPage( object data )
	{
		this.data = data;

		BackgroundColor = DXColors.Dark1;

		// Always vertical scroll only
		Orientation = ScrollOrientation.Vertical;

		// Underlying layout
		layout = new DXGridLayout
		{
			BackgroundColor = DXColors.Dark1,
			
			Padding = 0,
			RowSpacing = BasePadding,
			ColumnSpacing = BasePadding,
			
			Horizontal = LayoutOptions.Fill,
			Vertical = LayoutOptions.Fill,
			
			// Do NOT ignore
			IgnoreSafeArea = false
		};

		Content = layout;

		// Underlying data structure
		cards = [];

		// Defaults
		ScrollPosition = ScrollToPosition.Start;
	}

	// Adds a card to list on page
	protected void AddCard( DXCard card )
	{
		cards.Add( card );
	}

	// Updates card matching specified model without refreshing entire page
	public void UpdateCard( DXModel model )
	{
		foreach ( DXCard card in cards )
		{
			object cardData = card.Data;

			// Found matching card
			if ( (cardData != null) && cardData.Equals( model ) )
			{
				card.Update( model );
			}
		}
	}

	// Removes all cards from page
	protected void Clear()
	{
		cards.Clear();
		layout.ClearAll();
	}

	// Resets button sticky states on all cards
	public void Reset()
	{
		foreach ( DXCard card in cards )
		{
			card.Reset();
		}
	}

	// Used internally to determine fixed size card height
	private double GetCardHt()
	{
		return (cards.Count > 0) ? cards[0].GetViewHt() : -1;
	}

	// Scrolls page to preset position, defaults to top
	public void Scroll( bool animated = false )
	{
		switch ( ScrollPosition )
		{
			// Don't scroll empty (or Add New only) page
			case ScrollToPosition.End:
			{
				DXCard lastCard = cards[ ^1 ];

				ScrollToView( lastCard, animated );
				break;
			}
			// Top
			default:
			{
				ScrollToTop( animated );
				break;
			}
		}
	}

	// Adds label indicating card page is empty
	private void AddEmpty()
	{
		string text = DXString.Get( "card.empty", Title );

		// Empty
		DXLabel emptyLbl = new()
		{
			Text = text,
			TextColor = DXColors.Dark3,
			Font = DXFonts.RobotoBoldItalic,
			FontSize = 30,

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

		layout.AddStarRow( 33 );
		layout.AddStarRow( 67 );

		// Center in top 1/3 of page
		layout.Add( emptyLbl, 0, 0 );
	}

	/* Abstracts */

	// Reloads all cards on page, must be implemented by subclass
	public abstract void LoadCards();

	/* Layout */

	// Device/orientation specific layout
	public override void UpdateLayout( LayoutType type )
	{
		DXLog.Debug( "CardPage:{0}", Title );
		
		// Safe area handled externally
		Padding = BasePadding;
		
		// Number columns depends on device type/orientation
		switch ( type )
		{
			case LayoutType.Landscape: UpdateGrid( 3 ); break;
			case LayoutType.Portrait: UpdateGrid( 2 ); break;
			case LayoutType.MobileLandscape: UpdateGrid( 2 ); break;
			case LayoutType.MobilePortrait: UpdateGrid( 1 ); break;
		}

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

		// Universal for all pages
		DXSpinner.Stop();
	}

	// 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 )
		{
			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( GetCardHt() );
			}

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

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

					if ( index < count )
					{
						DXCard card = cards[ index ];

						// 'Add New' card is flat, no elevation
						if ( !card.IsNew )
						{
							layout.Add( card, col, row );
						}

						// WORKAROUND: Required for Android
						if ( layout.Contains( card ) )
						{
							layout.Remove( card );
						}
						
						layout.Add( card, col, row );
					}
				}
			}
		}
		// 'No <models> Yet'
		else
		{
			AddEmpty();
		}
	}
}

//
