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

using System.Text.Json.Serialization;
using Plugin.Firebase.Firestore;

namespace iStatVball3;

/*
 * Represents an entry for a particular zone (1-6, LIB 1-2) in a lineup. Each entry contains a player, the position of
 * the player in the lineup, and the applicable jersey number.
 *
 * Persisted as a map in the parent lineup NOT as a root level collection.
 */
public class LineupEntry : IFirestoreObject
{
	/* Constants */
	public const string NumberKey = "num";
	public const string AltNumberKey = "alt";

    // Lineup front/back row
    public enum Row
    {
        Unknown,
        Frontrow,
        Backrow
    };

    /* Properties */
    [FirestoreProperty("Zone")] public int Zone { get; set; }

    [FirestoreProperty("Position")] public string Position { get; set; }
    [FirestoreProperty("IsAltNumber")] public bool IsAltNumber { get; set; }

    // References
    [FirestoreProperty("PlayerId")] public string PlayerId { get; set; }

    /* Ignored */
    [JsonIgnore] public string Number => IsAltNumber ? Player?.AltNumber : Player?.Number;

    [JsonIgnore] public bool IsEmpty => Player == null;
    [JsonIgnore] public bool IsFrontRow => ZoneIsFrontRow( Zone );
    [JsonIgnore] public bool IsBackRow => ZoneIsBackRow( Zone );

    [JsonIgnore] public bool IsLibero => !IsEmpty && (Position == Lineup.LiberoKey);
    [JsonIgnore] public bool IsSetter => !IsEmpty && (Position == Lineup.SetterKey);

    // For WHP use
	[JsonIgnore] public bool IsDefault { get; set; }
	[JsonIgnore] public bool IsPrevious { get; set; }

	// References
	[JsonIgnore] public Player Player { get; set; }

	/* Methods */
	public LineupEntry()
	{}

	// Deep copies entry from specified existing entry
	public LineupEntry( LineupEntry entry )
	{
		if ( entry != null )
		{
			Zone = entry.Zone;

			Position = entry.Position;
			IsAltNumber = entry.IsAltNumber;

			PlayerId = entry.PlayerId;
			Player = entry.Player;
		}
	}

	// Constructs entry from specified player
	public LineupEntry( Player player )
	{
		Position = player.FirstPosition( true );
		IsAltNumber = false;

		PlayerId = player.RootId;		// MUST use root
		Player = player;
	}

	// Determines if all fields equal to specified entry
	public bool Equals( LineupEntry entry )
	{
		// Might be undefined
		if ( entry == null )
		{
			return false;
		}

		// Might be starting blank
		if ( IsEmpty && !entry.IsEmpty )
		{
			return false;
		}

		// Both empty
		if ( IsEmpty && entry.IsEmpty )
		{
			return true;
		}

		// All other fields must be equal (except zone)
		return Player.Equals( entry.Player ) && Number.Equals( entry.Number ) && Position.Equals( entry.Position );
	}

	// Determines if entries are equal based on unique player ID
	public bool Equals( Player player )
	{
		return !IsEmpty && (player != null) && player.Equals( Player );
	}

	/* Populate */

	// Populates player FK reference (no db)
	public void Populate( Season season )
	{
		Player = season.GetPlayer( PlayerId );
	}

	/* Utilities */

	// Determines if this lineup entry is front or back row
	public Row GetRow()
	{
		return GetRow( Zone );
	}

	// Determines if specified zone is in front or back row
	public static Row GetRow( int zone )
	{
		return ZoneIsBackRow( zone ) ? Row.Backrow : Row.Frontrow;
	}

	// Determines if specified zone is in backrow (5-6-1)
	public static bool ZoneIsBackRow( int zone )
	{
		return zone is 5 or 6 or 1;
	}

	// Determines if specified zone is frontrow (2-3-4)
	public static bool ZoneIsFrontRow( int zone )
	{
		return zone is 2 or 3 or 4;
	}

	// Determines if specified zone is a libero zone (7-8)
	public static bool ZoneIsLibero( int zone )
	{
		return zone is Lineup.LiberoZone1 or Lineup.LiberoZone2;
	}

	// Determines if specified zone in same row (front/back) as this entry
	public bool IsSameRow( int zone )
	{
		return GetRow( Zone ) == GetRow( zone );
	}

	// Determines if specified lineup entries contain given player
	public static bool Contains( List<LineupEntry> entries, Player player )
	{
		foreach ( LineupEntry entry in entries )
		{
			Player player2 = entry?.Player;

			// Match found
			if ( player2 != null && player2.Equals( player ) )
			{
				return true;
			}
		}

		// Not found
		return false;
	}

	// Returns entry from given list matching specified position
	public static LineupEntry GetEntry( List<LineupEntry> entries, string position )
	{
		return entries.FirstOrDefault( entry => entry.Position == position );
	}

	// Determines if any entry in specified list is empty
	public static bool IsListEmpty( List<LineupEntry> entries )
	{
		// Completely empty
		if ( (entries == null) || (entries.Count == 0) )
		{
			return true;
		}

		// Look for empty individual entry
		return entries.Any( entry => entry.IsEmpty );
	}
}

//
