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

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

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

namespace iStatVball3;

/*
 * An analysis form showing a vertical list of report cards. Each card can be of any available report type. For most
 * reports, a ReportBuilder is displayed at the top of the form allowing the user to configure the chart type, team,
 * dimensions, and filters for the reports.
 */
public class ReportForm : DXGridLayout
{
	/* Properties */

	// Data refresh control
	private bool IsUpdating { set { if ( builder != null ) builder.IsUpdating = value; } }

	/* Fields */

	// Underlying components
	private Builder builder;
	private DXContent reports;

	// Layout for each report type
	private Dictionary<string,ReportLayout> layouts;
	private ReportLayout activeLayout;

	// Setup
	private ReportConfig reportConfig;
	private DataConfig dataConfig;

	// State control
	private bool hasBuilder;
	private bool hasFilter;

	// Season scope match filtering
	private TagFilterView filterView;
	private DXPopup filterPopup;

	// Email export
	private ReportExporter reportExporter;

	/* Methods */

	// Post-construction initialization
	public async Task Init( ReportConfig config )
	{
		reportConfig = config;

		// Spacing
		BackgroundColor = DXColors.Dark1;

		Padding = 0;
		RowSpacing = 0;
		ColumnSpacing = 0;

		Horizontal = LayoutOptions.Fill;
		Vertical  = LayoutOptions.Fill;

		IgnoreSafeArea = true;
		
		// Allocate container
		layouts = new Dictionary<string, ReportLayout>();

		// MUST be created first
		reports = new DXContent();

		hasBuilder = HasBuilder( config.Dashboard );

		// Only show builder if needed
		if ( hasBuilder )
		{
			builder = new Builder( this );

			builder.Init( config );
			builder.SelectType( AnalyzeKeys.GridKey );
		}
		else
		{
			builder = null;

			// Report can be exported unless excluded in config.
			// NOTE: May have already been added in Builder.
			if ( HasExport() )
			{
				Shell.Instance.ToolBar.AddCustom( 1, "export", "export.item" );
			}
		}

		// Static layout on tablet
		if ( DXDevice.IsTablet )
		{
			Layout();
		}

		JsonDashboard json = config.Dashboard;
		bool isTeam1 = config.IsTeam1;

		// Configure query (non-builder ONLY)
		dataConfig = new DataConfig
		{
			// Default to grid
			Type = json.IsCustom ? AnalyzeKeys.CustomKey : JsonDashboard.GetDefaultType(),
			Key = json.Key,

			Scope = config.Scope,
			ScopeObject = config.ScopeObject,

			Organization = config.Organization,
			IsTeam1 = isTeam1,

			Team1 = config.Team1,
			Team2 = config.Team2,

			OuterDim = json.GetDefaultDimension( isTeam1 ),
			InnerDim = null,

			PlayerAccessId = Shell.CurrentUser.GetPermission()
		};

		// Execute
		await UpdateData( dataConfig );
	}

	// Determines if builder being used (at least one component selectable)
	private static bool HasBuilder( JsonDashboard json )
	{
		// More than 1 report type
		if ( json.Types is { Count: > 1 } )
		{
			return true;
		}

		// More than 1 team
		if ( json.Teams > 1 )
		{
			return true;
		}

		// More than 1 dimension
		return json.Dimensions is { Count: > 1 };
	}

	// Determines if PDF exports enabled for this report
	public bool HasExport()
	{
		User user = Shell.CurrentUser;
		JsonDashboard dashboard = reportConfig.Dashboard;

		bool enabled = dashboard.IsPdfEnabled || dashboard.IsCustom;
		bool access = (user != null) && ((user.Level >= User.LevelType.Media) || user.IsAdmin);

		// Must be enabled with Coach/Director permission
		return !reportConfig.HasSync && enabled && access;
	}

	// Show form after brief delay to avoid flicker
	public void Show()
	{
		hasFilter = (dataConfig.Scope == DataConfig.SeasonScope);

		ToolBar toolbar = Shell.Instance.ToolBar;

		// Remove sync
		if ( reportConfig.HasSync )
		{
			toolbar.RemoveCustom( 1 );
		}

		// Report can be exported to PDF (custom button added in Builder)
		if ( HasExport() )
		{
			toolbar.Custom1Tapped = OnExportTapped;
		}

		// Second button either filter
		if ( hasFilter )
		{
			toolbar.AddCustom( 2, "filter", "filter.filter" );
			toolbar.Custom2Tapped = OnFilterTapped;

			filterView?.Reset();
		}

		IsVisible = true;
	}

	// Fully hides form
	public void Hide()
	{
		ToolBar toolbar = Shell.Instance.ToolBar;

		// No longer need custom button(s)
		if ( HasExport() )
		{
			toolbar.RemoveCustom( 1 );
			toolbar.Custom1Tapped = null;
		}

		if ( hasFilter )
		{
			toolbar.RemoveCustom( 2 );
			toolbar.Custom2Tapped = null;
		}

		IsVisible = false;
	}

	// Refreshes data display for all reports on form
	public async Task UpdateData( DataConfig config )
	{
		// Remove existing report
		RemoveLayout();

		DXSpinner.Start();

		dataConfig = config;

		// Update all reports
		await UpdateData();

		// Update builder
		if ( hasBuilder )
		{
			bool filtered = (config.OuterFilter != null) || (config.InnerFilter != null);

			// Must filter here for builder
			DataStats stats = await DataFilter.Filter( config );

			// Update
			if ( (stats != null) && !filtered )
			{
				builder.UpdateData( config, stats );
			}
		}
	}

	// Refreshes display based on specified filtered stats
	private async Task UpdateData()
	{
		dataConfig.IsForceEligible = true;

		string type = dataConfig.Type;

		// Must re-create every time
		ReportLayout layout = new()
		{
			Type = type
		};

		layout.Init( reportConfig.Dashboard, dataConfig );
		layouts.Add( type, layout );

		// Refresh
		await layout.UpdateData( dataConfig );

		activeLayout = layout;
		reports.Content = activeLayout;
	}

	// Prepares form for data update
	private void RemoveLayout()
	{
		// Removes layout when switching report types
		if ( activeLayout != null )
		{
			activeLayout.IsVisible = false;

			Remove( activeLayout );
			layouts.Remove( activeLayout.Type );

			activeLayout = null;
		}
	}

	// Convenience access to Custom toolbar buttons
	private static DXIconButton GetCustomBtn( int number )
	{
		ToolBar toolBar = Shell.Instance.ToolBar;

		return toolBar.IsMoreMode ? toolBar.MoreBtn : ((number == 1) ? toolBar.Custom1Btn : toolBar.Custom2Btn);
	}

	/* Event Callbacks */

	// User exporting report to PDF
	private void OnExportTapped()
	{
		if ( DXData.HasConnection() )
		{
			if ( dataConfig.InnerDim == null )
			{
				// Check user setting
				switch ( Shell.Settings.ExportEmail )
				{
					// Local app (Apple/Google Mail)
					case Settings.EmailLocal:
	                {
						string subject = DXString.Get( "export.subject", reportConfig.Title );
				
						// Send immediately via native app
						OnExport( new ReportExportConfig()
						{
							IsLocal = true,
							Subject = subject
						});
				
						break;
	                }
					// Cloud provider (SendGrid)
					case Settings.EmailCloud:
					{
						Season season = dataConfig.GetSeason();
				
						// Show single/group email popup
						reportExporter = new ReportExporter( season )
						{
							Completed = OnExport,
							Cancelled = OnDone
						};
				
						reportExporter.Show();
						break;
					}
				}
			}
			// Cannot export multi-dimensional grid
			else
			{
				DXAlert.ShowError( "export.item", "export.err.dim", OnDone );
			}
		}
		// Connection required
		else
        {
			DXAlert.ShowNetworkError( "net.err.email" );
        }
	}

	// User confirmed export
	private async void OnExport( ReportExportConfig reportExportConfig )
	{
		DXSpinner.Start();
	
		// Special handling for custom, some reports do not have builder
		string key = reportConfig.IsCustom ? AnalyzeKeys.CustomKey : ((builder == null) ? AnalyzeKeys.GridKey : builder.SelectedType);
	
		// Momentum is set scope, scoring report only
		if ( (key == AnalyzeKeys.TrendKey) && dataConfig.IsMomentum )
		{
			key = AnalyzeKeys.MomentumKey;
		}
	
		// Retrieve list of all cards for currently selected type
		if ( layouts.TryGetValue( key, out var layout ) )
		{ 
			List<ReportCard> cards = layout.Cards;
	
			// Build configuration
			ExportConfig exportConfig = new()
			{
				IsLocal = reportExportConfig.IsLocal,
				
				FromAddress = reportExportConfig.FromAddress,
				ToAddresses = reportExportConfig.ToAddresses,
				ToNames = reportExportConfig.ToNames,
				
				Subject = reportExportConfig.Subject,
				Title = reportConfig.Title,
				
				DataConfig = dataConfig,
				Cards = cards,
				
				Json = reportConfig.Dashboard
			};
	
			bool pdf = (Shell.Settings.ExportFormat == Settings.FormatPdf);
	
			// PDF or Excel
			Exporter exporter = pdf ? new PDFExporter() : new ExcelExporter();
	
			// Export
			DXEmail.Result result = await exporter.Export( exportConfig );
	
			switch ( result )
			{
				// Success
				case DXEmail.Result.Success:
				{
					DXAlert.ShowOk( "export.title", "export.success", reportConfig.Title, OnDone );
					break;
				}
				// Email not supported
				case DXEmail.Result.ErrorUnsupported:
				{
					DXAlert.ShowError( "export.title", "export.err.support", OnDone );
					break;
				}
				// Other error
				case DXEmail.Result.Error:
				default:
				{
					DXAlert.ShowError( "export.item", "export.err", OnDone );
					break;
				}
			}
		}
	}

	// User tapped match tag filter
	private void OnFilterTapped()
	{
		Season season = dataConfig.ScopeObject as Season;

		// Create filter view (MUST re-create each time)
		filterView = new TagFilterView
		{
			Cleared = OnCleared,
			Filtered = OnFiltered
		};

		filterView.Init( season );

		// Create popup
		filterPopup = new DXPopup( DXString.Get( "filter.tag" ), filterView )
		{
			ViewWidth = 300,
			ViewHeight = 700,

			PopupClosed = OnDone
		};

		// Show
		filterPopup.ShowFromView( GetCustomBtn( 2 ) );
	}

	// User cleared all tag filters
	private async void OnCleared()
	{
		dataConfig.TagFilter = null;

		// Refresh data
		await UpdateData( dataConfig );

		OnDone();
	}

	// User configured new match filter
	private async void OnFiltered()
	{
		dataConfig.TagFilter = filterView.GetFilter();

		// Refresh data
		await UpdateData( dataConfig );

		OnDone();
	}

	// Export/filter successful
	private void OnDone()
	{
		DXSpinner.Stop();

		// Export only
		reportExporter?.Hide();
		reportExporter = null;

		Shell.Instance.ToolBar.ResetCustom();
	}

	/* Layout */

	// Device/orientation specific layout
	public override void UpdateLayout( LayoutType type )
	{
		IsUpdating = true;

		base.UpdateLayout( type );

		// Mobile must re-layout on orientation change
		if ( DXDevice.IsMobile )
		{
			Layout();
		}

		// Update children
		if ( hasBuilder )
		{
			builder.UpdateLayout( type );
		}

		activeLayout?.UpdateLayout( type );

		IsUpdating = false;
	}

	// Completely (re)create layout
	private void Layout()
	{
		ClearAll();

		// Builder
		if ( hasBuilder )
		{
			AddFixedRow( Builder.GetViewHt() );
			Add( builder, 0, 0 );
		}

		// Reports
		AddStarRow();

		Add( reports, 0, (hasBuilder ? 1 : 0) );

		// Must reset here
		reports.Content = activeLayout;
	}

	// Hide popup on rotate
	public void Rotate()
	{
		if ( IsVisible )
		{
			filterPopup?.Hide();
		}
	}
}

//
