/* 
 * 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.Utils;

namespace iStatVball3;

/*
 * Represents a Statistician (parent, volunteer, etc) for the parent Season.
 */
public class Statistician : RootModel
{
	/* Constants */
	public const string CollectionKey = "Statisticians";

    /* Properties */

    // Required
    [FirestoreProperty("Type")] public string Type { get; set; }
    [FirestoreProperty("FirstName")] public string FirstName { get; set; }
    [FirestoreProperty("LastName")] public string LastName { get; set; }

    // Optional
    [FirestoreProperty("Nickname")] public string Nickname { get; set; }
    [FirestoreProperty("Notes")] public string Notes { get; set; }

    // Record
    [FirestoreProperty("Won")] public int Won { get; set; }
    [FirestoreProperty("Lost")] public int Lost { get; set; }
    [FirestoreProperty("Tied")] public int Tied { get; set; }

    // Account Link (map)
    [FirestoreProperty("Link")] public Link Link { get; set; }

    // Parent (FK)
    [FirestoreProperty("SeasonId")] public string SeasonId { get; set; }

	/* Ignored */
	public string TypeName => DXString.GetLookupValue( "statistician.type", Type );
	public string FullName => $"{FirstName} {LastName}";
	public override string ObjectName => FullName;

	public bool HasLink => Link is { HasValue: true };

	// Parent
	public Season Season { get; set; }

	/* Methods */
	public Statistician()
	{
		BaseCollectionKey = CollectionKey;
	}

	// Tests equality based on unique ID
	public override bool Equals( object obj )
	{
		return (obj is Statistician stat) && stat.UniqueId.Equals( UniqueId );
	}

	// Generates unique hash code for lists
	public override int GetHashCode()
	{
		return UniqueId.GetHashCode();
	}

	/* Permissions */

	// Determines if user has permission to create Statisticians
	public static bool CanCreate( Season season, User user )
	{
		return user.Level switch
		{
			// Director/coach/stat can
			User.LevelType.Director or 
			User.LevelType.Coach or 
			User.LevelType.Statistician => !season.IsSample || user.IsAdmin,
			
			// No-one else can
			_ => false
		};
	}

	// Determines if user has permission to edit Statisticians
	public static bool CanEdit( User user )
	{
		return user.Level switch
		{
			// Director/coach/stat always can
			User.LevelType.Director or 
			User.LevelType.Coach or 
			User.LevelType.Statistician => true,
			
			// No-one else can
			_ => false
		};
	}

	// Determines if user has permission to analyze Statistician stats
	public bool CanAnalyze( User user )
	{
		return user.Level switch
		{
			// Only Director/Coach
			User.LevelType.Director or 
			User.LevelType.Coach => true,
			
			// No-one else
			_ => Season.IsSample
		};
	}

    /* Analyze */
    
	// Returns list of all matches for this Statistician
	public List<Match> GetMatches()
	{
	   List<Match> matches = [];
	   List<Match> matchList = Season.GetMatches();
	
	   // Only include matches for this statistician
	   foreach ( Match match in matchList )
	   {
		   if ( (match.Statistician != null) && match.Statistician.Equals( this ) )
		   {
				matches.Add( match );
		   }
	   }
	
	   return matches;
	}
	
	// Aggregates all data for analyzing scope of this Statistician
	public async Task<DataStats> Aggregate()
	{
		DataStats stats = new();
		List<Match> matches = GetMatches();
	
		// Append stats from all matches for statistician
		foreach ( Match match in matches )
		{
			stats.Add( await match.Aggregate() );
		}
	
		return stats;
	}
	
	// Aggregates all raw summary data for scope of this Statistician
	public StatSummary AggregateRaw()
	{
		StatSummary summary = new();
		List<Match> matches = GetMatches();
	
		// Aggregate summary data for all matches for statistician
		foreach ( Match match in matches )
		{
			summary.Add( match.AggregateRaw() );
		}
	
		return summary;
	}

	/* CRUD */

	// Reads and returns Statistician matching specified unique identifier
	public static async Task<Statistician> Read( string uniqueId )
	{
		return await Read<Statistician>( CollectionKey, uniqueId );
	}

	// Updates status for permission link
	public override async Task UpdateLink( string username, Link.StatusType status )
	{
		await UpdateLink( Link, username, status, "Link" );
	}

	// Updates won/lost/tied fields for this object (batched)
	public void UpdateRecord( IWriteBatch batch )
	{
		Won = 0; 
		Lost = 0; 
		Tied = 0;

		// Recount all matches
		foreach ( Match match in Season.Matches.Where( match => (match.Statistician != null) && match.Statistician.Equals( this ) ) )
		{
			if ( match.Won )
			{
				Won++;
			}
			else if ( match.Lost )
			{
				Lost++;
			}
			else if ( match.Tied )
			{
				Tied++;
			}
		}

		// Persist
		Update( batch, "Won", Won );
		Update( batch, "Lost", Lost );
		Update( batch, "Tied", Tied );
	}

	// Performs cascading delete for this Statistician
	public override async Task Delete( bool remove = false )
	{
		// Delete permissions from any user with access
		await Permission.Delete( UniqueId, Link );

		// No children to delete

		// Remove from parent
		if ( remove )
		{
			Season.Statisticians.Remove( this );
		}

		// Delete self
		await base.Delete( remove );
	}

	// Deletes all links for specified user for this object
	public override async Task DeleteLink( string username )
	{
		await DeleteLink( Link, username, "Link" );

		Link = null;
	}

	/* Import */

	// Creates new Statistician in specified season from existing object (batched)
	public static void Import( IWriteBatch batch, Season season, Statistician statistician )
	{
		Statistician newStatistician = new()
		{
			// Copy fields from existing object
			Type = statistician.Type,
			FirstName = statistician.FirstName,
			LastName = statistician.LastName,

			Nickname = statistician.Nickname,
			Notes = statistician.Notes,

			// Account Link
			Link = statistician.Link,

			// Start with existing image
			ImageUrl = statistician.ImageUrl,

			// Connect to this season
			SeasonId = season.UniqueId,
			Season = season
		};

		// Add to parent
		season.Statisticians.Add( newStatistician );

		// Connect roots
		newStatistician.Connect( batch, statistician );

		// Persist
		newStatistician.Create( batch );
	}
}

//
