/* 
 * 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 a link between a user account and a permission for a team entity (coach, player, etc). Used to track link
 * status as it moves from created, to pending, to granted. Persisted as a map within the associated entity NOT as a
 * separate document.
 */
public class Link : IFirestoreObject
{
	/* Constants */

	// Link status
	public enum StatusType
	{
		None,
		Pending,
		Granted,
		MultiGranted
	};

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

	/* Ignored */
	public bool HasValue => !string.IsNullOrEmpty( Username );
	public StatusType Status { get => (StatusType)StatusEnum; set => StatusEnum = (int)value; }

	/* Methods */
	public Link()
	{
		Status = StatusType.None;
	}

	// Returns link from specified list matching username
	public static Link GetLink( IList<Link> links, string username )
	{
		return links.FirstOrDefault( link => link.Username.Equals( username ) );
	}

	// Converts specified list of links to comma-delimited text string
	public static string GetText( IList<Link> links )
	{
		string text = null;

		if ( links != null )
		{
			text = string.Empty;
			int count = links.Count;

			// Build comma delimited list
			for ( int i = 0; i < count; i++ )
			{
				text += links[i].Username;

				if ( i < (count - 1) )
				{
					text += ", ";
				}
			}
		}

		return text;
	}

	// Returns specified list of links as list of text usernames
	public static List<string> GetUsernames( IList<Link> links )
	{
		List<string> usernames = new();

		if ( links != null )
		{
			// Add to list
			usernames.AddRange( from link in links where (link != null) select link.Username );
		}

		return usernames;
	}

	// Returns lowest status of any link in specified list
	public static StatusType GetStatus( IList<Link> links )
	{
		// No links
		if ( (links == null) || (links.Count == 0) )
		{
			return StatusType.None;
		}

		StatusType status = StatusType.Granted;

		// Find lowest value
		foreach ( Link link in links )
		{
			if ( link.Status < status )
			{
				status = link.Status;
			}
		}

		return status;
	}

	// Returns highest status from individual link and list of links
	public static StatusType GetMultiStatus( Link link, IList<Link> links )
	{
		StatusType status = link?.Status ?? StatusType.None;
		StatusType listStatus = GetStatus( links );

		// Special status if both fully granted
		if ( (status == StatusType.Granted) && (listStatus == StatusType.Granted) )
		{
			return StatusType.MultiGranted;
		}

		StatusType highest = (status.CompareTo( listStatus ) > 0) ? status : listStatus;

		// Otherwise use highest
		return highest;
	}

	/* CRUD */

	// Updates status for specified permission link
	public static async Task Update( Permission.LevelType level, string entityId, string username, StatusType status )
	{
		// MUST be called before reading associated entity
		LinkModel model = await GetEntity( level, entityId );

		// Player is only entity with multiple link types
		if ( level == Permission.LevelType.Fan )
		{
			(model as Player)?.UpdateFanLinks( username, status );
		}
		// All others 1:1
		else
		{
			model?.UpdateLink( username, status );
		}
	}

	// Used internally to return concrete data model based on link type
	private static async Task<LinkModel> GetEntity( Permission.LevelType level, string entityId )
	{
		return level switch
		{
			Permission.LevelType.Coach => await Coach.Read( entityId ),
			Permission.LevelType.Statistician => await Statistician.Read( entityId ),
			Permission.LevelType.Fan => await Player.Read( entityId ),
			Permission.LevelType.Player => await Player.Read( entityId ),
			Permission.LevelType.Media => await Team.Read( entityId ),

			_ => null,
		};
	}
}

//
