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

using System.Text;

using DXLib.UI;
using DXLib.UI.Alert;

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

using DXLib.Data;
using DXLib.Data.Model;

using DXLib.Utils;

namespace iStatVball3;

/*
 * Specialized card for Matches. Similar to CardSmall except with result badge and set totals/scores. Also adds End and
 * Export buttons.
 */
public sealed class MatchCard : CardBase
{
	/* Constants */

	// Export options
	private const string MaxPrepsKey = "maxpreps";
	private const string BoundKey = "bound";

	/* Fields */
	private readonly DXTextBadge badge;

	private readonly DXLabel scoreLbl;
	private readonly DXLabel setsLbl;

	private readonly DXButton endBtn;
	private readonly DXIconButton exportBtn;

	/* Methods */
	public MatchCard( Match match, bool tournParent, bool readOnly = false ) : base( readOnly )
	{
		bool ios = DXDevice.IsIOS;
		bool tablet = DXDevice.IsTablet;
		bool wide = DXDevice.IsTabletWide;

		/* Layout */

		// 5 Rows
		layout.AddStarRow( 37 );        // 0: labels
		layout.AddStarRow( 14 );        // 1: badge
		layout.AddStarRow( 14 );        // 2: score
		layout.AddStarRow( 08 );        // 3: sets
		layout.AddStarRow( 27 );        // 4: buttons

		// 3 columns
		layout.AddStarColumn( 70 );     // 0: other
		layout.AddStarColumn( 10 );     // 1: spacer
		layout.AddStarColumn( 20 );     // 2: image/icon

		/* Controls */

		bool deactivated = match.IsScrimmage;
		double opacity = deactivated ? DeactivatedOpacity : 1.0;

		// Card can be faded
		SetDeactivated( deactivated );

		// Labels
		labels.TitleLbl.FontSize = 18;

		labels.SubTitleLbl.Font = DXFonts.Roboto;
		labels.SubTitleLbl.FontSize = 13;

		layout.Add( labels, 0, 0, 2, 1 );

		// Image/icon
		layout.Add( imageArea, 2, 0 );

		// Badge
		badge = new DXTextBadge
		{
			Opacity = opacity,

			TextColor = DXColors.Light4,
			Margin = new Thickness( 10, 8, 10, 0 ),

			Horizontal = LayoutOptions.Start,
			Vertical = LayoutOptions.Start,

			Selected = OnBadgeSelected
		};

		badge.Adjust( 0, (tablet ? (wide ? -2 : 0) : (ios ? -1 : 0)) );

		layout.Add( badge, 0, 1 );

		// Score
		scoreLbl = new DXLabel
		{
			Opacity = opacity,

			Font = DXFonts.Oswald,
			FontSize = 26,

			Margin = new Thickness( 10, (ios ? -2 : -8), 10, 0 ),
		};

		layout.Add( scoreLbl, 0, 2 );

		// Sets
		setsLbl = new DXLabel
		{
			Opacity = opacity,

			TextColor = DXColors.Dark4,
			Margin = new Thickness( 10, -1, 10, 0 ),

			Font = DXFonts.Oswald,
			FontSize = 12
		};

		layout.Add( setsLbl, 0, 3 );

		// Analyze/Edit buttons
		buttons.Margin = new Thickness( 10, 0, 0, 7 );
		buttons.Vertical = LayoutOptions.End;

		layout.Add( buttons, 0, 4, 2, 1 );

		// Lock
		if ( readOnly || GlobalLock )
		{
			layout.Add( lockBtn, 2, 4 );
		}

		// End (in-progress matches only)
		if ( match.IsInProgress )
		{
			endBtn = new DXButton
			{
				Resource = "alert.end",
				Type = DXButton.ButtonType.Negative,

				IsSticky = true,
				ButtonWd = 80,

				ButtonTapped = OnEndTapped,
			};

			endBtn.Init();

			// All sets must be ended (MUST be after init)
			endBtn.IsDisabled = match.SetInProgress();
			
			buttons.Add( endBtn );
		}

		const double btnSize = 26;
		const double btnPad = 10;

		// Export (ended matches only)
		if ( match.IsEnded && (!match.Season.IsSample || Shell.CurrentUser.IsAdmin) )
		{
			exportBtn = new DXIconButton
			{
				Resource = "export",
				IconColor = DXColors.Dark4,
				Size = btnSize,

				Margin = new Thickness( 0, 6, btnPad, 0 ),

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

				IsSticky = true,
				ButtonTapped = OnExportTapped
			};

			layout.Add( exportBtn, 1, 4, 2, 1 );
		}

		/* Match Specific */

		Data = match;

		// Image
		DefaultIcon = "match";
		ImageUrl = match.GetImageUrl();
		ImageColor = match.Color;

		// Labels
		if ( !tournParent )
		{
			// Android holds space for empty label
			if ( match.Tournament != null )
			{
				SuperTitle = match.Tournament.Name;
			}
		}

		Title = match.Name;
		SubTitle = match.Detail;

		// Init custom components
		Update( match );
	}

	// Updates card fields without requiring page refresh
	public override void Update( DXModel model )
	{
		Match match = model as Match;

		UpdateBadge( match );
		UpdateScore( match );
		UpdateSets( match );
	}

	// Creates badge for current match state
	private void UpdateBadge( Match match )
	{
		string resource = null;

		if ( match.IsEnded )
		{
			// Won/Lost/Tied
			resource = match.GetResultRsrc();
		}
		else
		{
			// RallySync
			if ( match.IsRallySynced )
			{
				resource = "match.sync";
			}
			// From Video
			else if ( match.IsVideo )
			{
				resource = "match.video";
			}
			// From Paper
			else if ( match.IsPaper )
			{
				resource = "match.paper";
			}
			// In Progress
			else if ( match.IsInProgress )
			{
				resource = "match.progress";
			}
			// Future
			else if ( match.IsFuture )
			{
				resource = "match.future";
			}
			// New
			else if ( match.IsNew )
			{
				resource = "match.new";
			}
		}

		badge.ResourceUpper = resource;
		badge.Color = GetColor( match );
	}

	// Sets score text and color
	private void UpdateScore( Match match )
	{
		// No score for new match
		if ( match.IsNew )
		{
			scoreLbl.IsVisible = false;
		}
		// X-Y (green for win, else gray)
		else
		{
			scoreLbl.Text = $"{match.Sets1}-{match.Sets2}";
			scoreLbl.TextColor = GetColor( match );
			scoreLbl.IsVisible = true;
		}
	}

	// Creates list of set results
	private void UpdateSets( Match match )
	{
		// No results for new set
		if ( match.IsNew )
		{
			setsLbl.IsVisible = false;
		}
		else
		{
			StringBuilder builder = new();

			IList<int> scores1 = match.Scores1;
			IList<int> scores2 = match.Scores2;

			int count = Math.Min( scores1.Count, scores2.Count );

			// 'X-Y, X-Y' for each set of match
			for ( int i = 0; i < count; i++ )
			{
				builder.Append( $"{scores1[i]}-{scores2[i]}" );

				if ( i < (count - 1) ) builder.Append( ", " );
			}

			setsLbl.Text = builder.ToString();
			setsLbl.IsVisible = true;
		}
	}

	// Returns color to be used for badge/score based on match state
	private static Color GetColor( Match match )
	{
		Color color = DXColors.Dark1;

		if ( match.IsEnded )
		{
			// Won
			if ( match.Won )
			{
				color = DXColors.Positive;
			}
			// Lost
			else if ( match.Lost )
			{
				color = DXColors.Dark4;
			}
			// Tied
			else if ( match.Tied )
			{
				color = DXColors.Dark3;
			}
		}
		else
		{
			// RallySync
			if ( match.IsRallySynced )
			{
				color = DXColors.Negative;
			}
			// From Video
			else if ( match.IsVideo )
			{
				color = DXColors.Negative;
			}
			// From Paper
			else if ( match.IsPaper )
			{
				color = DXColors.Accent4;
			}
			// In Progress
			else if ( match.IsInProgress )
			{
				color = DXColors.Action;
			}
			// Future
			else if ( match.IsFuture )
			{
				color = DXColors.Accent5;
			}
			// New
			else if ( match.IsNew )
			{
				color = DXColors.Warn;
			}
		}

		return color;
	}

	// Required implementation
	public override double GetViewHt()
	{
		return CardSmall.CardHt;
	}

	// Used to exclude buttons from card tap area
	protected override bool IsChildBounds( Point point )
	{
		return base.IsChildBounds( point ) || ((endBtn != null) && endBtn.Contains( point )) ||
											  ((exportBtn != null) && exportBtn.Contains( point ));
	}

	/* Event Callbacks */

	// Pass through badge taps
	private void OnBadgeSelected()
	{
		HandleTap( badge.Bounds.Center );
	}

	// END

	// User tapped match End button, show confirmation prompt
	private void OnEndTapped( object sender )
	{
		if ( Data is Match match )
		{
			string msg1;

			int sets1 = match.Sets1;
			int sets2 = match.Sets2;

			// Match ended in tie
			if ( sets1 == sets2 )
			{
				msg1 = DXString.Get( "match.end.tie" );
			}
			// Winner
			else
			{
				string winner = (sets1 > sets2) ? match.Team1Name : match.Team2Name;

				msg1 = DXString.Get( "match.end.win", winner );
			}

			int won = Math.Max( sets1, sets2 );
			int lost = Math.Min( sets1, sets2 );

			// 'End match with TeamFoo winning (X-Y)?'
			string msg2 = DXString.Get( "match.end.result", won.ToString(), lost.ToString() );
			string msg = msg1 + msg2;

			DXAlert.ShowNegativeCancelRaw( DXString.Get( "match.end" ), msg, "alert.end", OnEndConfirmed, OnEndCancelled );
		}
	}

	// User confirmed end of match
	private async void OnEndConfirmed()
	{
		if ( Data is Match match )
		{
			// Mark as ended, persist data, update results, etc
			await match.End();

			// Update UI
			Shell.Instance.PageStack.Refresh();
		}
	}

	// User cancelled ending match
	private void OnEndCancelled()
	{
		endBtn.Reset();
	}

	// EXPORT

	// User tapped card export button
	private void OnExportTapped()
	{
        if ( DXData.HasConnection() )
        {
            // Create menu
            DXMenu menu = new()
			{
				Title = "match.export",
   
				HasIcons = true,
				IconColor = DXColors.Transparent,
				IconAdjustY = 2,
   
				ItemSelected = OnItemSelected,
				Cancelled = OnExportDone
			};
   
			List<DXItem> items = DXString.GetLookupList( "match.export" );
   
			// Show popup
			menu.SetItems( items );
			menu.ShowFromView( exportBtn );
        }
        else
        {
            DXAlert.ShowNetworkError( "net.err.export", null, OnExportDone );
        }
    }

    // User selected item from export menu
    private void OnItemSelected( DXItem item )
	{
		if ( item != null )
		{
			Match match = Data as Match;

			switch ( item.Key )
			{
				// MaxPreps
				case MaxPrepsKey:
				{
					DXAlert.ShowOkCancel( "maxpreps2.export", "maxpreps2.msg", OnMaxPreps, OnExportDone );
					break;
				}
				// Bound
				case BoundKey:
				{
					// Configure
					VBExporter exporter = new()
					{
						Match = match,
						RootBtn = exportBtn
					};

					// Start export UI flow
					exporter.StartExport();
					break;
				}
			}
		}
		// Cancelled
		else
		{
			OnExportDone();
		}
	}
    
	// User confirmed MaxPreps export
	private async void OnMaxPreps()
	{
		Match match = Data as Match;

		// New auto-upload
		if ( Shell.Settings.ExportMaxPreps == Settings.MaxPrepsAuto )
		{
			await MP2Exporter.Export( match, OnExportDone );
		}
		// Old file export
		else
		{
			await MPExporter.Export( match, OnExportDone );
		}
	}

	// Export interaction complete, reset state
	private void OnExportDone()
	{
		exportBtn.Reset();

		DXSpinner.Stop();
	}
}

//
