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

namespace iStatVball3;

/*
 * Represents an opposing team for one or more matches in a season.
 */
public class Opponent : RootModel
{
	/* Constants */
	public const string CollectionKey = "Opponents";

	// Anonymous opponent for match
	public const string AnonOpponent = "anon";

	// Used for ISV import when team not defined
	public const string BlankOpponent = "?";

	// Color if not user defined
	public static readonly Color DefaultColor = Color.FromArgb( "9E9E9E" );

    /* Properties */

    // Required
    [FirestoreProperty("Organization")] public string Organization { get; set; }
    [FirestoreProperty("Team")] public string Team { get; set; }
    [FirestoreProperty("Abbreviation")] public string Abbreviation { get; set; }

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

    [FirestoreProperty("ColorValue")] public long? ColorValue { get; set; }

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

    // MaxPreps link
	[FirestoreProperty("MaxPreps")] public MP2School MaxPreps { get; set; }

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

	/* Ignored */
	public string FullName => $"{Organization} {Team}";
	public string ShortName => Organization;
	public override string ObjectName => FullName;

	public Color Color { get => ColorValue.HasValue ? Color.FromUint( (uint)ColorValue ) : DefaultColor; set => ColorValue = value.ToUint(); }

	// MaxPreps
	public bool HasMaxPreps => MaxPreps != null;
	public bool IsHighSchool => Season.IsHighSchool;

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

	/* Methods */
	public Opponent()
	{
		BaseCollectionKey = CollectionKey;

		// Defaults
		ColorValue = DefaultColor.ToUint();
	}

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

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

	/* Permissions */

	// Determines if user has permission to create Opponents
	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 Opponents
	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 Opponent 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 played against this opponent
	public List<Match> GetMatches()
	{
		List<Match> matches = [];
		List<Match> matchList = Season.GetMatches();
		
		// Only include matches for this opponent
		foreach ( Match match in matchList )
		{
		   if ( (match.Opponent != null) && match.Opponent.Equals( this ) )
		   {
				matches.Add( match );
		   }
		}
		
		return matches;
   }
	
	// Aggregates all data for analyzing scope of this Opponent
	public async Task<DataStats> Aggregate()
	{
		DataStats stats = new();
		List<Match> matches = GetMatches();
	
		// Append stats from all matches for opponent
		foreach ( Match match in matches )
		{
			stats.Add( await match.Aggregate() );
		}
	
		return stats;
	}
	
	// Aggregates all raw summary data for scope of this Opponent
	public StatSummary AggregateRaw()
	{
		StatSummary summary = new();
		List<Match> matches = GetMatches();
	
		// Aggregate summary data for all matches for opponent
		foreach ( Match match in matches )
		{
			summary.Add( match.AggregateRaw() );
		}
	
		return summary;
	}

	/* CRUD */

	// 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.Opponent != null) && match.Opponent.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 on this Opponent
	public override async Task Delete( bool remove = false )
	{
		// No children to delete

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

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

	/* Import */

	// Creates new Opponent in specified season from existing object (batched)
	public static void Import( IWriteBatch batch, Season season, Opponent opponent )
	{
		Opponent newOpponent = new()
		{
			// Copy fields from existing object
			Organization = opponent.Organization,
			Team = opponent.Team,
			Abbreviation = opponent.Abbreviation,

			Mascot = opponent.Mascot,
			Location = opponent.Location,
			Notes = opponent.Notes,

			ColorValue = opponent.ColorValue,

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

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

		// Add to parent
		season.Opponents.Add( newOpponent );

		// Connect roots
		newOpponent.Connect( batch, opponent );

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

//
