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

using Plugin.Firebase.Firestore;

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

using DXLib.UI.Control;
using DXLib.UI.Control.Tree;
using DXLib.UI.Control.Button;

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

using DXLib.Utils;

namespace iStatVball3;

/*
 * Utility class used to display Roster, Tournament, Coach, Statistician, Opponent, and Venue objects from the previous
 * season(s) of all teams in the organization. The objects are displayed in a tree-based UI, so that the user can choose
 * what data to import into the new season.
 */
public class SeasonImporter
{
	/* Constants */
	private const double PopupWd = 325;
	private const double PopupHt = 550;
	
	/* Events */
	public Action Confirmed { get; set; }
	public Action Cancelled { get; set; }

	/* Properties */
	public bool HasChanges { get; private set; }

	/* Fields */
	private readonly DXGridLayout layout;

	private readonly DXTree tree;
	private readonly DXButton okBtn;

	private DXPopup popup;

	// External refs
	private Team importTeam;
	private Season importSeason;

	/* Methods */
	public SeasonImporter()
	{
		// Layout
		layout = new DXGridLayout()
		{
			BackgroundColor = DXColors.Light4,

			Padding = 0,
			RowSpacing = 10,
			ColumnSpacing = 5,

			WidthRequest = PopupWd,
			HeightRequest = PopupHt,
			
			Horizontal = LayoutOptions.Fill,
			Vertical = LayoutOptions.Fill
		};

		// Importer tree
		tree = new DXTree
		{
			BackgroundColor = DXColors.Light4,
			
			Margin = new Thickness( 15, 15, 15, 0 ),
			AutoExpand = true,
			
			Horizontal = LayoutOptions.Fill,
			Vertical = LayoutOptions.Fill,
			
			Checked = OnItemChecked
		};

		// Inner layout
		DXGridLayout btnLayout = new()
		{
			BackgroundColor = DXColors.Light2,

			Margin = 0,
			Padding = new Thickness( 10, 10, 10, 10 ),
			ColumnSpacing = 10,

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

		const double cancelWd = 75;
		
		// Cancel
		DXButton cancelBtn = new()
		{
			Type = DXButton.ButtonType.Neutral,
			Resource = "alert.cancel",
			ButtonWd = cancelWd,

			Horizontal = LayoutOptions.End,
			Vertical = LayoutOptions.Center,
			
			ButtonTapped = OnCancelTapped
		};

		cancelBtn.Init();

		const double okWd = DXButton.DefaultWd;
		
		// OK
		okBtn = new DXButton
		{
			Type = DXButton.ButtonType.Positive,
			Resource = "alert.ok",
			ButtonWd = okWd,

			IsDisabled = true,

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

			ButtonTapped = OnOkTapped
		};

		okBtn.Init();
		
		// 3 inner columns
		btnLayout.AddStarColumn();					// 0: pad
		btnLayout.AddFixedColumn( cancelWd );		// 1: cancel 
		btnLayout.AddFixedColumn( okWd );			// 2: ok
		
		btnLayout.Add( cancelBtn, 1, 0 );
		btnLayout.Add( okBtn, 2, 0 );

		double buttonsHt = (DXButton.DefaultHt + btnLayout.Padding.VerticalThickness);
		
		// 2 rows
		layout.AddStarRow();						// 0: tree
		layout.AddFixedRow( buttonsHt );			// 1: cancel/ok

		layout.Fill( DXPopup.DefaultHeaderColor, 0, 1 );

		// Add components
		layout.Add( tree, 0, 0 );
		layout.Add( btnLayout, 0, 1 );
	}

	// Post construction initialization
	public async Task Init( Team team, Season season )
	{
		importTeam = team;
		importSeason = season;

		// Importing into existing season
		if ( importSeason != null )
		{
			await importSeason.PopulateFull();
		}

		// Populate
		await CreateTree();
	}

	// Creates tree with root node for each team
	private async Task CreateTree()
	{
		tree.Clear();

		// Sort all teams in org
		List<Team> teams = importTeam.Organization.Teams.OrderBy( t => t.Name ).ToList();

		// Add root node for each team
		foreach ( Team team in teams )
		{
			List<Season> seasons = team.GetSeasons( importSeason, true );

			// Only show team if at least 1 season
			if ( seasons.Count > 0 )
			{
				// Add team node
				DXTreeDatum root = tree.AddRoot( team.UniqueId, team.Name );

				// Add node for each prior season
				foreach ( Season previous in seasons )
				{
					await previous.PopulateImport();

					// Add season node
					DXTreeDatum node = DXTree.AddNode( root, previous.UniqueId, previous.Name, true );
					
					// Add import types for season
					AddNodes( node, importSeason, previous );
				}
			}
		}
	}

	// Adds node for specified season with child nodes for all import types
	private static void AddNodes( DXTreeDatum node, Season season, Season previous )
	{
		AddNode( node, "player", "player.roster", season?.PlayerList, previous.PlayerList );
		AddNode( node, "tournament", "tournament.plural", season?.TournamentList, previous.TournamentList );
		AddNode( node, "coach", "coach.plural", season?.CoachList, previous.CoachList );
		AddNode( node, "statistician", "statistician.plural", season?.StatisticianList, previous.StatisticianList );
		AddNode( node, "opponent", "opponent.plural", season?.OpponentList, previous.OpponentList );
		AddNode( node, "venue", "venue.plural", season?.VenueList, previous.VenueList );
	}

	// Adds node with child models into specified node
	private static void AddNode( DXTreeDatum node, string key, string resource, List<DXModel> current, List<DXModel> previous )
	{
		List<DXModel> models = RootModel.GetModels( current, previous );

		// Only add models not already in current season
		if ( models.Count > 0 )
		{
			DXTree.AddNode( node, key, DXString.Get( resource ), true, models );
		}
	}

	// Displays importer utility in modal popup
	public void Show( View view )
	{
		// Display modal popup
		popup = new DXPopup( "season.import", layout )
		{
			IsModal = true,
			
			Padding = 0,
			Margin = 0,
			
			ViewWidth = PopupWd,
			ViewHeight = PopupHt
		};

		popup.ShowFromView( view );

		DXSpinner.Stop();
	}

	// Imports all selected objects from previous season
	public async Task Import( Season season )
	{
		// May be newly created season
		importSeason = season;

		if ( HasChanges )
		{
			IWriteBatch batch = DXData.StartBatch();

			// Import each object type
			ImportPlayer( batch );
			ImportTournament( batch );
			ImportCoach( batch );
			ImportStatistician( batch );
			ImportOpponent( batch );
			ImportVenue( batch );

			await DXData.CommitBatch( batch );
		}
	}

	// Returns list of all selected objects of specified type from all teams
	private List<RootModel> GetSelected( string key )
	{
		// Get selected across all teams
		List<DXModel> items = tree.GetSelectedModels( key );

		Dictionary<string,RootModel> models = new();

		// Exclude duplicates
		foreach ( DXModel item in items )
		{
			if ( item is RootModel model )
			{
				models.TryAdd( model.RootId, model );
			}
		}

		// Sort by name
		return models.Values.OrderBy( m => m.ObjectName ).ToList();
	}

	// Imports all selected Players
	private void ImportPlayer( IWriteBatch batch )
	{
		List<RootModel> players = GetSelected( "player" );

		foreach ( Player player in players.Cast<Player>() )
		{
			Player.Import( batch, importSeason, player );
		}
	}

	// Imports all selected Tournaments
	private void ImportTournament( IWriteBatch batch )
	{
		List<RootModel> tournaments = GetSelected( "tournament" );

		foreach ( Tournament tournament in tournaments.Cast<Tournament>() )
		{
			Tournament.Import( batch, importSeason, tournament );
		}
	}

	// Imports all selected Coaches
	private void ImportCoach( IWriteBatch batch )
	{
		List<RootModel> coaches = GetSelected( "coach" );

		foreach ( Coach coach in coaches.Cast<Coach>() )
		{
			Coach.Import( batch, importSeason, coach );
		}
	}

	// Imports all selected Statisticians
	private void ImportStatistician( IWriteBatch batch )
	{
		List<RootModel> statisticians = GetSelected( "statistician" );

		foreach ( Statistician statistician in statisticians.Cast<Statistician>() )
		{
			Statistician.Import( batch, importSeason, statistician );
		}
	}

	// Imports all selected Opponents
	private void ImportOpponent( IWriteBatch batch )
	{
		List<RootModel> opponents = GetSelected( "opponent" );

		foreach ( Opponent opponent in opponents.Cast<Opponent>() )
		{
			Opponent.Import( batch, importSeason, opponent );
		}
	}

	// Imports all selected Venues
	private void ImportVenue( IWriteBatch batch )
	{
		List<RootModel> venues = GetSelected( "venue" );

		foreach ( Venue venue in venues.Cast<Venue>() )
		{
			Venue.Import( batch, importSeason, venue );
		}
	}

	/* Event Callbacks */

	// Tree node was (un)checked, update OK button
	private void OnItemChecked()
	{
		var items = tree.GetCheckedNodes();

		okBtn.IsDisabled = (items == null) || (items.Count == 0);
	}

	// User confirmed import selections
	private void OnOkTapped( object sender )
	{
		HasChanges = true;

		popup.Hide();

		// Callback listener
		Confirmed?.Invoke();
	}

	// User dismissed importer popup
	private void OnCancelTapped( object sender )
	{
		popup.Hide();

		// Callback listener
		Cancelled?.Invoke();
	}
}

//
