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

using DXLib.Email;
using DXLib.Data.Model;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Represents an invitation to a user to access a particular entity (team, player, etc) at a particular permission level.
 * Provides functionality for sending invitation emails. The user does not need to be existing.
 */
public class Invite : DXModel
{
	/* Constants */
	public const string CollectionKey = "Invites";

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

    [FirestoreProperty("TeamId")] public string TeamId { get; set; }
    [FirestoreProperty("OrganizationId")] public string OrganizationId { get; set; }
    [FirestoreProperty("EntityId")] public string EntityId { get; set; }

    [FirestoreProperty("LevelEnum")] public int LevelEnum { get; set; }

	/* Ignored */
	public Permission.LevelType Level { get => (Permission.LevelType)LevelEnum; set => LevelEnum = (int)value; }

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

	// Creates new invite and sends invitation email
	public static async Task CreateAndSend( string username, PermissionKeys keys )
	{
		// Check for existing invite
		List<Invite> invites = await ReadByAll( username, keys.EntityId, keys.Level );

		// Create and send (if does not exist)
		if ( invites.Count == 0 )
		{
			Invite invite = new()
			{
				Username = username,

				TeamId = keys.TeamId,
				OrganizationId = keys.OrganizationId,
				EntityId = keys.EntityId,

				Level = keys.Level
			};

			// Persist
			await invite.Create();

			// Send email
			await Send( username, keys.Team, keys.Level );
		}
	}

	// Sends email invitation via SendGrid dynamic template
	private static async Task Send( string username, Team team, Permission.LevelType level )
	{
		string levelStr = User.GetLevelLabel( (User.LevelType)level );

		// Async send
		await DXEmail.Send( new DXEmailConfig
		{
			FromAddress = DXString.Get( "email.address" ),
			FromName = DXString.Get( "email.name" ),

			ToAddress = username,
			ToName = null,

			TemplateId = InviteEmail.TemplateId,
			TemplateData = new InviteEmail
			{
				Team = team.FullName,
				Level = levelStr
			}
		});

		// Notify user
		DXAlert.ShowOkRaw( DXString.Get( "invite.sent" ), DXString.Get( "invite.sent.msg", levelStr, username ) );
	}

	/* CRUD */

	// Reads and returns any invites for specified user
	public static async Task<IEnumerable<Invite>> ReadByUsername( string username )
	{
		return await ReadList<Invite>( CollectionKey, "Username", username );
	}

	// Reads and returns any invites matching all required fields
	private static async Task<List<Invite>> ReadByAll( string username, string entityId, Permission.LevelType level )
	{
		IQuery query = GetCollection( CollectionKey ).WhereEqualsTo( "Username", username )
													 .WhereEqualsTo( "EntityId", entityId );
		// Optionally restrict to specific level
		if ( level != Permission.LevelType.ALL )
		{
			query = query.WhereEqualsTo( "LevelEnum", (int)level );
		}

		IQuerySnapshot<Invite> snapshot = await query.GetDocumentsAsync<Invite>();

		List<Invite> invites = [];

		// Support multiple matches
		if ( snapshot is { Documents: not null } )
		{
			foreach ( IDocumentSnapshot<Invite> document in snapshot.Documents )
			{
				invites.Add( document.Data );
			}
		}

		return invites;
	}

	// Deletes any outstanding invites for specified user and entity
	public static async Task Delete( string username, string entityId, Permission.LevelType level )
	{
		List<Invite> invites = await ReadByAll( username, entityId, level );

		// Delete all matches
		foreach ( Invite invite in invites )
		{
			await invite.Delete();
		}
	}
}

//
