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

namespace iStatVball3;

/*
 * Encapsulates all fields necessary for configuring a stats analysis query.
 */
public class DataConfig
{
	/* Constants */

	// Available analysis scopes
	public const string OrganizationScope = "org";
	public const string TeamScope = "team";
	public const string SeasonScope = "season";

	public const string TournamentScope = "tourn";
	public const string TournamentDayScope = "day";

	public const string MatchScope = "match";
	public const string SetScope = "set";

	public const string LineupScope = "lineup";
	public const string StatisticianScope = "statistician";
	public const string OpponentScope = "opponent";
	public const string VenueScope = "venue";

	// Available data set types
	public const string SkillsData = "skills";
	public const string SideoutData = "sideout";
	public const string PlayingData = "playing";
	public const string ScoringData = "scoring";

	public const string BoxscoreData = "boxscore";
	public const string MatchData = "match";
	public const string ResultsData = "results";

	/* Properties */
	public string Scope { get; set; }
	public object ScopeObject { get; set; }

	public string Action { get; set; }
	public string Type { get; set; }
	public string Key { get; set; }

	public Organization Organization { get; set; }
	public bool IsTeam1 { get; set; }

	public Team Team1 { get; set; }
	public Opponent Team2 { get; set; }

	public string OuterDim { get; set; }
	public string InnerDim { get; set; }

	public List<object> OuterFilter { get; set; }
	public List<object> InnerFilter { get; set; }

	public string DataSet { get; set; }

	// Restricted access for Player/Fan account
	public string PlayerAccessId { get; set; }

	// Used for season scope match tag filtering
	public TagFilter TagFilter { get; set; }

	// Includes raw summary data?
	public bool HasSummary { get; set; }

	// Can user manually force data reload?
	public bool IsForceEligible { get; set; }

	// Maximum character length of first column label
	public int MaxLabelLen { get; set; }

	/* Convenience Accessors */
	public bool IsPlaying => DataSet == PlayingData;
	public bool IsScoring => DataSet == ScoringData;
	public bool IsSkills => DataSet == SkillsData;

	// Multi-level?
	public bool IsNested => InnerDim != null;

	// Career stat root mapping
	public bool IsCareer => (Scope == OrganizationScope) || (Scope == TeamScope) || (Scope == SeasonScope);

	// Momentum Chart eligible?
	public bool IsMomentum => (Scope == SetScope) && IsScoring;

	// Derived
	public string TeamId => IsTeam1 ? Team1?.UniqueId : Team2?.UniqueId;
	public string TeamName => IsTeam1 ? Organization.Name : Team2?.ShortName;

	/* Calculated Results */
	public Dictionary<string,string> RootTable;

	public DataDimension Dimension { get; set; }
	public DataMetrics Totals { get; set; }

	/* Methods */
	public DataConfig()
	{
		RootTable = new Dictionary<string,string>();
	}
	
	// Deep copies all properties from specified configuration
	public DataConfig( DataConfig config )
	{
		Scope = config.Scope;
		ScopeObject = config.ScopeObject;

		Action = config.Action;
		Type = config.Type;
		Key = config.Key;

		Organization = config.Organization;
		IsTeam1 = config.IsTeam1;

		Team1 = config.Team1;
		Team2 = config.Team2;

		OuterDim = config.OuterDim;
		InnerDim = config.InnerDim;

		OuterFilter = config.OuterFilter;
		InnerFilter = config.InnerFilter;

		DataSet = config.DataSet;

		PlayerAccessId = config.PlayerAccessId;
		TagFilter = config.TagFilter;

		HasSummary = config.HasSummary;

		IsForceEligible = config.IsForceEligible;
		MaxLabelLen = config.MaxLabelLen;
	}

	// Determines if current query should force full data reload
	public bool ShouldForce()
	{
		// Only some queries eligible
		if ( IsForceEligible )
		{
			// Only in-progress sets not being recorded by this user
			Set recording = Shell.CurrentUser.RecordingSet;

			switch ( Scope )
			{
				// Force set
				case SetScope:
				{
					if ( ScopeObject is Set set )
					{
						return set.IsInProgress && !set.Equals( recording );
					}

					break;
				}
				// Force match
				case MatchScope:
				{
					if ( ScopeObject is Match match )
					{
						return match.IsInProgress && !match.Contains( recording );
					}

					break;
				}
			}
		}

		return false;
	}

	// Returns season object for configured scope
	public Season GetSeason()
	{
		return Scope switch
		{
			SeasonScope => (ScopeObject as Season),
			MatchScope => (ScopeObject as Match)?.Season,
			SetScope => (ScopeObject as Set)?.Match.Season,

			TournamentScope => (ScopeObject as Tournament)?.Season,
			TournamentDayScope => (ScopeObject as TournamentDay)?.Tournament.Season,

			LineupScope => (ScopeObject as Lineup)?.Season,
			StatisticianScope => (ScopeObject as Statistician)?.Season,
			OpponentScope => (ScopeObject as Opponent)?.Season,
			VenueScope => (ScopeObject as Venue)?.Season,

			_ => null
		};
	}

	/* Metrics */

	// Returns metrics for specified player
	public DataMetrics GetMetrics( Player player )
	{
		string key = player.RootId;

		return Dimension.Metrics.GetValueOrDefault( key );
	}

	// Returns metrics for specified rotation
	public DataMetrics GetMetrics( int rotation )
	{
		string key = rotation.ToString();

		return Dimension.Metrics.GetValueOrDefault( key );
	}

	/* Access */

	// Determines if player should be included given access restrictions
	public bool HasAccess( string rootId )
	{
		return (PlayerAccessId == null) || PlayerAccessId.Equals( rootId );
	}

	// Determines if player should be included given access restrictions
	public bool HasAccess( Player player, bool allowNull = false )
	{
		if ( IsTeam1 )
		{
			return allowNull || ((player != null) && HasAccess( player.RootId ));
		}

		return true;
	}

	// Determines if player should be included given access restrictions
	private bool HasAccess( Stat stat )
	{
		return HasAccess( stat.Player, stat.Set.IsRallyLow );
	}

	/* Filter */

	// Filters specified list of stats by access and dimension(s)
	public DataStats Filter( DataStats stats )
	{
		DataStats data = new();

		// Must filter each stat individually
		foreach ( Stat stat in stats )
		{
			if ( Filter( stat, false ) )
			{
				data.Add( stat );
			}
		}

		return data;
	}

	// Determines if specified stat should be included in filter
	public bool Filter( Stat stat, bool actionOnly, int playerNum = 1 )
	{
		// Actions must be filtered
		if ( stat.IsAction )
		{
			// Check for access restriction
			if ( HasAccess( stat ) )
			{
				// Check against outer/inner filters (if any)
				return DataFilter.FilterDimension( DataDimension.Level.Outer, this, stat, playerNum ) &&
					   DataFilter.FilterDimension( DataDimension.Level.Inner, this, stat, playerNum );
			}
			else
			{
				return false;
			}
		}

		// Optionally include non-action
		return !actionOnly;
	}

	// Determines if player should be included given dimension filter(s)
	public bool FilterDimension( object filterObj )
	{
		// Outer
		if ( OuterFilter != null )
		{
			if ( OuterDim == KeyDimension.PlayerKey )
			{
				Player player = filterObj as Player;

				if ( !OuterFilter.Contains( player ) )
				{
					return false;
				}
			}
		}

		// Inner
		if ( InnerFilter != null )
		{
			if ( InnerDim == KeyDimension.PlayerKey )
			{
				Player player = filterObj as Player;

				if ( !InnerFilter.Contains( player ) )
				{
					return false;
				}
			}
		}

		// Include
		return true;
	}
}

//
