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

using DXLib.Data;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Encapsulates all variables and statistics for Playing Time related metrics. Provides utility methods for variable
 * accumulation and statistic calculation.
 */
public class MetricsPlaying : DataMetrics
{
	// Variables
	public int Time { get; set; }
	public int Points { get; set; }
	public int Touches { get; set; }

	public int TimeTotal { get; set; }
	public int PointTotal { get; set; }
	public int TouchTotal { get; set; }

	// Statistics
	public float TimePercent { get; set; }
	public float PointPercent { get; set; }
	public float TouchPercent { get; set; }

	public float TimePerSet { get; set; }
	public float PointsPerSet { get; set; }
	public float TouchesPerSet { get; set; }

	// Formatted times
	public string TimeStr { get; set; }
	public string TimeTotalStr { get; set; }
	public string TimePerSetStr { get; set; }

	/* Methods */
	public MetricsPlaying( bool total = false ) : base( total )
	{}

	/* Report Accumulation */

	// Accumulates all dimensional variables from specified stats list
	public static void AccumulateDimension( DataConfig config, DataStats stats )
	{
		config.Dimension = new DataDimension();
		config.Totals = new MetricsPlaying( true );

		MetricsPlaying totals = (MetricsPlaying)config.Totals;

		// Accumulate list of all players in scope
		List<Player> players = DataFilter.GetPlayers( config );

		// Create row for each player
		foreach ( Player player in players )
		{
			// Check dimension filter
			if ( (config.OuterFilter == null) || config.OuterFilter.Contains( player ) )
			{
				BuildDimension( config, player );
			}
		}

		// Stats list already filtered for playing time
		foreach ( Stat stat in stats )
		{
			// Time/points comes from point stat
			if ( stat.IsPoint )
			{
				AccumulatePoint( config, players, stat.Point );

				int time = stat.Point.Duration;

				// Must accumulate totals here
				totals.Time += time;
				totals.TimeTotal += time;

				totals.Points += 1;
				totals.PointTotal += 1;
			}
			// Touches comes from action
			else if ( stat.IsAction )
			{
				AccumulateTouch( config, players, stat );

				// Must accumulate totals here
				totals.Touches += 1;
				totals.TouchTotal += 1;
			}
		}
	}

	// Accumulates player specific playing time metrics from specified point
	private static void AccumulatePoint( DataConfig config, List<Player> players, StatPoint point )
	{
		int time = point.Duration;

		// Time/point credited only to players on court
		for ( int rot = 0; rot < Lineup.BaseEntries; rot++ )
		{
			Player player = GetPlayer( players, point.PlayerIds1[ rot ] );

			if ( player != null )
			{
				// Add to player dimension
				if ( config.GetMetrics( player ) is MetricsPlaying metrics )
				{
					metrics.Time += time;
					metrics.Points += 1;
				}
			}
		}

		// Total time/points credited to ALL players
		foreach ( Player player in players )
		{
			if ( config.GetMetrics( player ) is MetricsPlaying metrics )
			{
				metrics.TimeTotal += time;
				metrics.PointTotal += 1;
			}
		}
	}

	// Accumulates player specific ball contact metrics from specified stat
	private static void AccumulateTouch( DataConfig config, List<Player> players, Stat stat )
	{
		// Touch credited only to stat player
		if ( stat.Player != null )
		{
			if ( config.GetMetrics( stat.Player ) is MetricsPlaying metrics )
			{
				metrics.Touches += 1;
			}
		}

		// Total touches credited to ALL players
		foreach ( Player player in players )
		{
			if ( config.GetMetrics( player ) is MetricsPlaying metrics )
			{
				metrics.TouchTotal += 1;
			}
		}
	}

	// Builds dimension (row) entry for specified player
	private static void BuildDimension( DataConfig config, Player player )
	{
		// Validate access control (dimension filter NA)
		if ( config.HasAccess( player ) )
		{
			// Keyed by root ID
			string key = player.RootId;
			string label = player.GetAnalyzeName( config.MaxLabelLen );

			var metricsList = config.Dimension.Metrics;

			// Prevent duplicates
			if ( !metricsList.ContainsKey( key ) )
			{
				// Create new dimension
				MetricsPlaying metrics = new()
				{
					Type = KeyDimension.PlayerKey,
					TypeKey = null,
					TypeLabel = null,

					TypeObject = player,

					Key = key,
					Label = label
				};

				metricsList.Add( key, metrics );
			}
		}
	}

	/* Dashboard Accumulation */

	// Accumulates all variables for specified stat
	public override void Accumulate( DataConfig config, Stat stat, int playerNum = 1 )
	{
		// Time/points 
		if ( stat.IsPoint )
		{
			Time += stat.Point.Duration;
			Points += 1;
		}
		// Touches
		else if ( stat.IsAction )
		{
			Touches++;
		}
	}

	/* Calculate */

	// Calculates all statistics for pre-accumulated variables
	public override void Calculate()
	{
		// Percent
		TimePercent = (TimeTotal > 0) ? (Time / (float)TimeTotal) : FloatNA;
		PointPercent = (PointTotal > 0) ? (Points / (float)PointTotal) : FloatNA;
		TouchPercent = (TouchTotal > 0) ? (Touches / (float)TouchTotal) : FloatNA;

		float sets = SetsPlayed;
		bool hasSets = (sets > 0);

		// Per Set
		TimePerSet = hasSets ? (Time / sets) : FloatNA;
		PointsPerSet = hasSets ? (Points / sets) : FloatNA;
		TouchesPerSet = hasSets ? (Touches / sets) : FloatNA;

		// Time formatting (Xh Ym Zs)
		TimeStr = DXUtils.FromDuration( Time );
		TimeTotalStr = DXUtils.FromDuration( TimeTotal );
		TimePerSetStr = hasSets ? DXUtils.FromDuration( (int)TimePerSet ) : DXData.NaN;
	}
}

//
