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

using DXLib.UI;

using DXLib.UI.Form;
using DXLib.UI.Alert;
using DXLib.UI.Layout;
using DXLib.UI.Container;

using DXLib.Utils;

namespace iStatVball3;

/*
 * Base class for all forms that include account links. An additional control list is provided for editing links.
 * Corresponding permissions will be created/deleted as the form is saved.
 */
public class LinkForm : DXForm
{
	/* Constants */
	public static readonly Color DefaultColor = DXColors.Accent1;

	/* Fields */
	private readonly DXScroll linkScroll;
	private readonly DXVerticalLayout linkLayout;
	private readonly DXFormControlList linkList;

	/* Methods */
	public LinkForm( object data, string dataType, bool readOnly = false ) : base( data, dataType, readOnly, true, false )
	{
		// Combined area is scrollable
		linkScroll = new DXScroll
		{
			Orientation = ScrollOrientation.Vertical,
			BackgroundColor = SecondaryList.Color,

			Padding = 0,
			Margin = 0
		};

		// Lists are stacked
		linkLayout = new DXVerticalLayout
		{
			BackgroundColor = DefaultColor,

			Padding = 0,
			Margin = 0,
			Spacing = 0
		};

		linkScroll.Content = linkLayout;

		// Extended link fields
		linkList = new DXFormControlList( false )
		{
			Color = DefaultColor,
			Title = "form.links",

			IsReadOnly = readOnly
		};
	}

	// Post-construction initialization
	public override void Init()
	{
		base.Init();

		// Init extended fields
		linkList.Init();
	}

	// Returns username value from specified link field
	public string GetLink( string key )
	{
		DXFormControl control = linkList.GetControl( key );

		// 'Add New' form does not have link field
		if ( control != null )
		{
			string list = control.GetObject() as string;

			// Trim whitespace
			return DXUtils.RemoveSpaces( list );
		}

		return null;
	}

	// Returns list of link values from comma delimited field
	public List<string> GetLinks( string key )
	{
		string list = GetLink( key );

		return list?.Split( ",", StringSplitOptions.RemoveEmptyEntries ).ToList();
	}

	// Used internally to create permission keys for link updating
	protected PermissionKeys CreateKeys( Permission.LevelType level, Team team )
	{
		return data is not LinkModel model ? null : new PermissionKeys
		{
			Level = level,
			Team = team,

			OrganizationId = team.OrganizationId,
			TeamId = team.UniqueId,
			EntityId = model.UniqueId
		};
	}

	// Alerts user following successful account link
	private static void ShowSuccess( string username, Permission.LevelType level )
	{
		string title = DXString.Get( "link.success" );

		string levelStr = User.GetLevelLabel( (User.LevelType)level );
		string msg = DXString.Get( "link.success.msg", levelStr, username );

		DXAlert.ShowOkRaw( title, msg );
	}

	/* Permissions */

	// Creates an individual link and corresponding permission
	protected static async Task<Link> CreateLink( string username, PermissionKeys keys )
	{
		return await UpdateLink( username, null, keys );
	}

	// Updates an individual link and corresponding permission
	protected static async Task<Link> UpdateLink( string username, Link link, PermissionKeys keys )
	{
		Link newLink = link;

		string previous = link?.Username;

		// Delete removed permission
		if ( previous != null )
		{
			if ( (username == null) || !username.Equals( previous ) )
			{
				await RemovePermission( previous, keys );

				newLink = null;
			}
		}

		// Create new permission
		if ( username != null )
		{
			if ( (previous == null) || !username.Equals( previous ) )
			{
				newLink = new Link { Username = username };

				// Create permission
				bool granted = await AddPermission( username, keys );

				// Create link (persisted with form update/create)
				newLink.Status = granted ? Link.StatusType.Granted : Link.StatusType.Pending;

				// Success
				if ( granted ) ShowSuccess( username, keys.Level );
			}
		}

		return newLink;
	}

	// Creates a list of links and corresponding permissions
	protected static async Task CreateLinks( LinkModel model, List<string> usernames, PermissionKeys keys )
	{
		await UpdateLinks( model, usernames, null, keys );
	}

	// Updates a list of links and corresponding permissions
	protected static async Task UpdateLinks( LinkModel model, List<string> usernames, IList<Link> links, PermissionKeys keys )
	{
		List<string> previous = Link.GetUsernames( links );

		// Delete any removed permissions
		if ( previous != null )
		{
			foreach ( string prev in previous )
			{
				if ( (usernames == null) || !usernames.Contains( prev ) )
				{
					// Delete link
					await model.DeleteLinks( prev );

					// Delete permission
					await RemovePermission( prev, keys );
				}
			}
		}

		// Create for any added permissions
		if ( usernames != null )
		{
			foreach ( string username in usernames )
			{
				if ( (previous == null) || !previous.Contains( username ) )
				{
					Link link = new()
					{
						Username = username
					};

					// Create permission
					bool granted = await AddPermission( username, keys );

					// Create link (persisted with form update/create)
					link.Status = granted ? Link.StatusType.Granted : Link.StatusType.Pending;
					links.Add( link );

					// Success
					if ( granted )
					{
						ShowSuccess( username, keys.Level );
					}
				}
			}
		}
	}

	// Creates new permission (or sends invite) for specified user
	private static async Task<bool> AddPermission( string username, PermissionKeys keys )
	{
		bool granted = false;

		if ( !string.IsNullOrEmpty( username ) )
		{
			User user = await User.ReadByUsername( username );

			// New user, invite to install app
			if ( user == null )
			{
				await Invite.CreateAndSend( username, keys );
			}
			// Existing user
			else
			{
				// Avoid duplicate invites
				await Invite.Delete( username, keys.EntityId, keys.Level );

				// Subscription level too low, invite user to upgrade
				if ( user.Level < (User.LevelType)keys.Level )
				{
					await Invite.CreateAndSend( username, keys );
				}
				// Correct level, grant permission
				else
				{
					granted = true;

					await Permission.Create( user, keys );
				}
			}
		}

		return granted;
	}

	// Removes permission corresponding to specified link
	private static async Task RemovePermission( string username, PermissionKeys keys )
	{
		await Permission.Delete( username, keys );

		// Delete any pending invitations
		await Invite.Delete( username, keys.EntityId, keys.Level );
	}

	/* Abstracts */

	// Determines if any base or link control has changed value
	protected override bool HasChanges()
	{
		return base.HasChanges() || linkList.HasChanges();
	}

	// Determines if all base and link controls have valid values
	public override bool IsValid()
	{
		bool valid = base.IsValid() && linkList.IsValid();

		buttons.SaveEnabled = valid;

		return valid;
	}

	// Adds extended link control to list
	public void AddControl( DXFormControl control )
	{
		linkList.Add( control, false, IsReadOnly );
	}

	/* Layout */

	// Custom link layout
	public override void UpdateLayout( LayoutType type )
	{
		linkLayout.Clear();

		base.UpdateLayout( type );
	}

	// Landscape (4:3)
	protected override void Landscape()
	{
		base.Landscape();

		// Replace optional list with scrollable optional/links
		if ( HasData )
		{
			Layout.Remove( SecondaryList.View );

			linkLayout.Add( SecondaryList.View );
			linkLayout.Add( linkList.View );

			Layout.Add( linkScroll, 2, 1 );
		}
	}

	// Portrait (3:4)
	protected override void Portrait()
	{
		base.Portrait();

		// Replace optional list with scrollable optional/links
		if ( HasData )
		{
			Layout.Remove( SecondaryList.View );

			linkLayout.Add( SecondaryList.View );
			linkLayout.Add( linkList.View );

			Layout.Add( linkScroll, 1, 2 );
		}
	}

	// Mobile landscape
	protected override void MobileLandscape()
	{
		base.MobileLandscape();

		// Replace optional list with optional/links
		if ( HasData )
		{
			LayoutL.Remove( SecondaryList.View );

			linkLayout.Add( SecondaryList.View );
			linkLayout.Add( linkList.View );

			LayoutL.Add( linkLayout, 2, 1 );
		}
	}

	// Mobile portrait
	protected override void MobilePortrait()
	{
		base.MobilePortrait();

		// Links added to bottom
		if ( HasData )
		{
			LayoutP.Add( linkList.View );
		}
	}
}

//
