/* 
 * 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.Layout;
using DXLib.UI.Container;

using DXLib.UI.Control;
using DXLib.UI.Control.Tree;
using DXLib.UI.Control.Button;

using DXLib.UI.Form;
using DXLib.UI.Form.Control;

using DXLib.Utils;

namespace iStatVball3;

/*
 * Implements the UI for exporting analysis reports. The user can choose between single or group email sending. Single
 * send presents basic To:/From: address fields. Group send allows the user to choose recipients from any eligible linked
 * model type:
 *   - Players
 *   - Coaches
 *   - Statisticians
 *   - Fans
 *   - Media
 */
public class ReportExporter : DXPopup
{
	/* Constants */
	private const double Pad = 24;

	// Recipient modes
	private const string SingleKey = "single";
	private const string GroupKey = "group";

	/* Events */
	public Action<ReportExportConfig> Completed { get; set; }
	public Action Cancelled { get; set; }

	/* Properties */
	private bool IsGroupMode => modeKey == GroupKey;

	/* Fields */

	// Common
	private readonly DXGridLayout layout;
	private readonly DXButton sendBtn;

	// Single
	private readonly DXTextField fromTxt;
	private readonly DXTextField toTxt;

	// Group
	private DXLabel groupLbl;
	private DXTree groupTree;

	// Single or group mode?
	private string modeKey;

	// External ref
	private readonly Season season;

	/* Methods */
	public ReportExporter( Season season )
	{
		this.season = season;

		IsModal = true;

		// Layout
		layout = new DXGridLayout
		{
			Padding = 0,
			RowSpacing = 5,
			ColumnSpacing = 5,

			BackgroundColor = DXColors.Light4
		};

		// Single/Group
		DXSegmentBar segmentBar = new()
		{
			Mode = DXSegmentBar.SegmentMode.Text,

			FillColor = DXColors.Dark3,
			TextColor = DXColors.Light4,
			SelectColor = DXColors.Light4,

			SegmentWd = 80,
			SegmentHt = 35,
			SegmentFontSize = 15,

			Horizontal = LayoutOptions.Center,
			Vertical = LayoutOptions.Center,

			Selected = OnSelected
		};

		segmentBar.Init();

		segmentBar.AddSegmentText( SingleKey, DXString.GetUpper( "export.single" ) );
		segmentBar.AddSegmentText( GroupKey, DXString.GetUpper( "export.group" ) );

		// Group NA for career exports
		if ( season == null )
		{
			segmentBar.Disable( GroupKey, true );
		}

		// Always start in single mode
		modeKey = SingleKey;
		segmentBar.SelectKey( SingleKey );

		string email = Shell.CurrentUser.Username;

		// From:
		fromTxt = new DXTextField
		{
			IsRequired = true,
			Type = DXTextField.TextType.Email,
			Hint = DXFormControl.HintType.Email,

			Title = "export.from",
			Text = email,

			Margin = new Thickness( Pad, 0, Pad, 0 ),

			Horizontal = LayoutOptions.Center,
			Vertical = LayoutOptions.End,

			ControlChanged = UpdateSend
		};

		fromTxt.Init();
		fromTxt.SetState( DXFormControl.ControlState.Normal );

		// To: (single only)
		toTxt = new DXTextField
		{
			IsRequired = true,
			Type = DXTextField.TextType.Email,
			Hint = DXFormControl.HintType.Email,

			Title = "export.to",
			Text = email,

			Margin = new Thickness( Pad, 0, Pad, 0 ),

			Horizontal = LayoutOptions.Center,
			Vertical = LayoutOptions.Start,

			ControlChanged = UpdateSend
		};

		toTxt.Init();
		toTxt.SetState( DXFormControl.ControlState.Normal );

		// Cancel
		DXButton cancelBtn = new()
		{
			Type = DXButton.ButtonType.Neutral,
			Resource = "alert.cancel",

			ButtonWd = 80,
			Margin = 0,

			Horizontal = LayoutOptions.End,
			Vertical = LayoutOptions.Center,

			ButtonTapped = OnCancelTapped
		};

		cancelBtn.Init();
		
		// Send
		sendBtn = new DXButton
		{
			Type = DXButton.ButtonType.Positive,
			Resource = "export.send",

			ButtonWd = 75,
			Margin = 0,

			Horizontal = LayoutOptions.Start,
			Vertical = LayoutOptions.Center,

			IsSticky = true,
			ButtonTapped = OnSendTapped
		};

		sendBtn.Init();
		
		// 2 columns
		layout.AddStarColumn( 53 );		// 0: cancel
		layout.AddStarColumn( 47 );		// 1: ok

		// 5 rows
		layout.AddFixedRow( 45 );		// 0: segment
		layout.AddFixedRow( 80 );		// 1: from
		layout.AddAutoRow();			// 2: group to:
		layout.AddStarRow();			// 3: single to: / group tree
		layout.AddFixedRow( 50 );       // 4: buttons

		// Single/Group
		layout.Fill( DXColors.Dark3, 0, 0, 2, 1 );
		layout.Add( segmentBar, 0, 0, 2, 1 );

		// From:
		layout.Add( fromTxt, 0, 1, 2, 1 );

		// Cancel/OK
		layout.Fill( DefaultHeaderColor, 0, 4, 2, 1 );
		layout.Add( cancelBtn, 0, 4 );
		layout.Add( sendBtn, 1, 4 );

		// Fixed size
		ViewWidth = 400;
		ViewHeight = 450;

		// Default to single
		LayoutSingle();

		SetTitle( DXString.Get( "export.title" ) );
		SetContent( layout );
	}

	// Builds single/group recipient list
	private ReportExportConfig GetExportConfig()
	{
		// Group
		if ( IsGroupMode )
		{
			List<string> addresses = [];
			List<string> names = [];

			// Players
			foreach ( DXTreeDatum player in groupTree.GetSelected( Permission.PlayerKey ) )
			{
				addresses.Add( player.Key );
				names.Add( player.Text );
			}

			// Coaches
			foreach ( DXTreeDatum coach in groupTree.GetSelected( Permission.CoachKey ) )
			{
				addresses.Add( coach.Key );
				names.Add( coach.Text );
			}

			// Statisticians
			foreach ( DXTreeDatum statistician in groupTree.GetSelected( Permission.StatisticianKey ) )
			{
				addresses.Add( statistician.Key );
				names.Add( statistician.Text );
			}

			// Fans
			foreach ( DXTreeDatum fan in groupTree.GetSelected( Permission.FanKey ) )
			{
				addresses.Add( fan.Key );
				names.Add( null );
			}

			// Media
			foreach ( DXTreeDatum media in groupTree.GetSelected( Permission.MediaKey ) )
			{
				addresses.Add( media.Key );
				names.Add( null );
			}

			// Config
			return new ReportExportConfig()
			{
				IsLocal = false,

				FromAddress = fromTxt.Text,

				ToAddresses = addresses,
				ToNames = names
			};
		}

		// Single
		return new ReportExportConfig()
		{
			FromAddress = fromTxt.Text,
			ToAddresses = [ toTxt.Text ],
		};
	}

	// Updates send button enabled state based on input control validity
	private void UpdateSend()
	{
		bool fromValid = fromTxt.IsValid();

		// Group
		if ( IsGroupMode )
		{
			bool treeValid = (groupTree.GetSelectedCount() > 0);

			sendBtn.IsDisabled = !fromValid || !treeValid;
		}
		// Single
		else
		{
			bool toValid = toTxt.IsValid();

			sendBtn.IsDisabled = !fromValid || !toValid;
		}
	}

	/* Layout */

	// Lays out form for specified single/group selection
	private void Layout( string key )
	{
		// Group
		if ( key == GroupKey )
		{
			LayoutGroup();
		}
		// Single
		else
		{
			LayoutSingle();
		}
	}

	// Lays out form for single recipient selection
	private void LayoutSingle()
	{
		// Remove group controls
		if ( groupTree != null )
		{
			layout.Remove( groupLbl );
			layout.Remove( groupTree );
		}

		// Add single controls
		layout.Add( toTxt, 0, 3, 2, 1 );
	}

	// Lays out form for group recipient selection
	private void LayoutGroup()
	{
		// Remove single controls
		layout.Remove( toTxt );

		// Lazily create group controls
		if ( groupTree == null )
		{
			// To:
			groupLbl = new DXLabel
			{
				Resource = "export.to",

				FontSize = 12,
				TextColor = DXColors.Dark1,

				Margin = new Thickness( Pad, 0, Pad, 0 ),
				Vertical = LayoutOptions.Start
			};

			// Tree
			groupTree = new DXTree
			{
				AutoExpand = false,

				Margin = new Thickness( Pad, 0, Pad, 0 ),
				Horizontal = LayoutOptions.Fill,
				Vertical = LayoutOptions.Start,

				Checked = UpdateSend
			};

			// Populate hierarchical tree
			CreateTree();
		}

		// Add group controls
		layout.Add( groupLbl, 0, 2, 2, 1 );
		layout.Add( groupTree, 0, 3, 2, 1 );
	}

	/* Tree */

	// Creates hierarchical tree with root node for each recipient type
	private void CreateTree()
	{
		AddPlayers();
		AddCoaches();
		AddStatisticians();
		AddFans();
		AddMedia();
	}

	// Adds all eligible Player email recipients to tree
	private void AddPlayers()
	{
		List<Player> players = season.GetPlayers();

		// Count eligible recipients
		int count = players.Sum( player => player.HasLink ? 1 : 0 );

		// Root node
		DXTreeDatum node = groupTree.AddRoot( Permission.PlayerKey, DXString.Get( "player.plural" ), (count > 0) );

		// Only add child node if eligible
		foreach ( Player player in players )
		{
			if ( player.HasLink )
			{
				DXTree.AddNode( node, player.Link.Username, player.FullName );
			}
		}
	}

	// Adds all eligible Coach email recipients to tree
	private void AddCoaches()
	{
		List<Coach> coaches = season.GetCoaches();

		// Count eligible recipients
		int count = coaches.Sum( coach => coach.HasLink ? 1 : 0 );

		// Root node
		DXTreeDatum node = groupTree.AddRoot( Permission.CoachKey, DXString.Get( "coach.plural" ), (count > 0) );

		// Only add child node if eligible
		foreach ( Coach coach in coaches )
		{
			if ( coach.HasLink )
			{
				DXTree.AddNode( node, coach.Link.Username, coach.FullName );
			}
		}
	}

	// Adds all eligible Statistician email recipients to tree
	private void AddStatisticians()
	{
		List<Statistician> statisticians = season.GetStatisticians();

		// Count eligible recipients
		int count = statisticians.Sum( statistician => statistician.HasLink ? 1 : 0 );

		// Root node
		DXTreeDatum node = groupTree.AddRoot( Permission.StatisticianKey, DXString.Get( "statistician.plural" ), (count > 0) );

		// Only add child node if eligible
		foreach ( Statistician statistician in statisticians )
		{
			if ( statistician.HasLink )
			{
				DXTree.AddNode( node, statistician.Link.Username, statistician.FullName );
			}
		}
	}

	// Adds all eligible Fan email recipients to tree
	private void AddFans()
	{
		List<Player> players = season.GetPlayers();

		// Count eligible recipients
		int count = players.Sum( player => player.HasFanLink ? 1 : 0 );

		// Root node
		DXTreeDatum node = groupTree.AddRoot( Permission.FanKey, DXString.Get( "export.fan" ), (count > 0) );

		// Only add child node if eligible
		foreach ( Player player in players )
		{
			if ( player.HasFanLink )
			{
				List<string> fans = Link.GetUsernames( player.FanLinks );

				// Player can have multiple fans
				foreach ( string fan in fans )
				{
					string label = $"{player.FullName} ({fan})";

					// 'Jane Doe (jsmith@foo.com)'
					DXTree.AddNode( node, fan, label );
				}
			}
		}
	}

	// Adds all eligible Media email recipients to tree
	private void AddMedia()
	{
		Team team = season.Team;

		// Root node
		DXTreeDatum node = groupTree.AddRoot( Permission.MediaKey, DXString.Get( "export.media" ), team.HasMediaLink );

		// Only add child node if eligible
		List<string> links = Link.GetUsernames( team.MediaLinks );

		// Team can have multiple media contacts
		foreach ( string link in links )
		{
			// 'jdoe@foo.com'
			DXTree.AddNode( node, link, link );
		}
	}

	/* Event Callbacks */

	// User toggled single/group selection, re-layout
	private void OnSelected( string key )
	{
		modeKey = key;

		Layout( key );

		// Validate single/group
		UpdateSend();
	}

	// User cancelled email export, callback listener
	private void OnCancelTapped( object sender )
	{
		Hide();

		Cancelled?.Invoke();
	}

	// User ready to send email(s)
	private void OnSendTapped( object sender )
	{
		DXSpinner.Start();

		// Build recipient list
		ReportExportConfig config = GetExportConfig();

		// Callback listener
		Completed?.Invoke( config );
	}
}

/*
 * Support class used to encapsulate fields for an individual report recipient as selected in the ReportExporter interface.
 */
public class ReportExportConfig
{
	/* Properties */
	public bool IsLocal { get; set; }

	public string FromAddress { get; set; }

	public List<string> ToAddresses { get; set; }
	public List<string> ToNames { get; set; }

	public string Subject { get; set; }
}

//
