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

using DXLib.Data.Model;

using DXLib.Log;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Main UI shell for entire app. Most high-level UI containers are created and managed here. They are simply shown/hidden
 * rather than being recreated multiple times. The Record and Tool UIs, as well as Data entry and Analyze UIs, are shown
 * as overlays (forms) on top of the current mode UI. Shell is a singleton for easy access throughout the app.
 */
public class Shell : DXPage
{
	/* Properties */

	// Reference to currently logged-in user
	public static User CurrentUser { get; set; }
	public static Settings Settings => CurrentUser.Settings;

	// Legacy or RallyFlow engine?
	public static bool IsLegacy => !Settings.IsRally;

	// High-level containers accessible globally
	public AppBar AppBar { get; }
	public ToolBar ToolBar => AppBar.ToolBar;
	public PathBar PathBar { get; }

	public LaunchStack LaunchStack { get; }
	public PageStack PageStack { get; }
	
	// Record UI
	public RecordForm RecordForm { get; private set; }
	public bool IsRecording => RecordForm is { IsVisible: true };

	// Analyze
	public DashboardForm DashboardForm { get; }
	public ReportForm ReportForm { get; }

	// Tools
	private ToolForm CurrentTool { get; set; }

	// Main display area
	public static double ContentHt { get; private set; }

	// Master layout
	private new DXAbsoluteLayout Layout { get; }

	// Lock UI to portrait orientation?
	public bool ForcePortrait { get => forcePortrait; set { forcePortrait = value; DXDevice.LockOrientation( value ); } }

	/* Fields */

	// Used for all create/edit and analyze forms
	private readonly DXContent dataForm;
	private readonly DXContent dataForm2;

	// Layout control
	private bool forcePortrait;

	// Singleton
	private static Shell instance;

	/* Methods */

	// Singleton constructor
	private Shell()
	{
		BackgroundColor = DXColors.Dark1;
		
		// Master layout
		Layout = new DXAbsoluteLayout
		{
			BackgroundColor = DXColors.Dark1,
			
			Margin = 0,
			Padding = 0,
			
			// Required for full bleed over safe areas
			IgnoreSafeArea = true
		};

		// Header
		AppBar = new AppBar
		{
			IsVisible = false,
			HasBackButton = false,

			BackTapped = OnBackTapped
		};

		// Child containers (all start hidden)
		PathBar = new PathBar {	IsVisible = false };
		LaunchStack = new LaunchStack { IsVisible = false };
		PageStack = new PageStack { IsVisible = false };

		// Overlays
		dataForm = new DXContent { IsVisible = false };
		dataForm2 = new DXContent { IsVisible = false };
	
		DashboardForm = new DashboardForm { IsVisible = false };
		ReportForm = new ReportForm { IsVisible = false };

		// Add child containers (sized later, must be added in z-order)
		Layout.Add( LaunchStack );
		Layout.Add( PageStack );

		Layout.Add( PathBar );
		Layout.Add( AppBar );

		// Must be on top because of appbar shadow
		Layout.Add( DashboardForm );
		Layout.Add( ReportForm );

		Content = Layout;
	}

	// Returns singleton instance
	public static Shell Instance
	{
		get
		{
			// Lazy instantiation
			instance ??= new Shell();

			return instance;
		}
	}

	/* General */

	// Sets color of native status bar
	public void SetStatusBarColor( Color color )
	{
		DXDevice.SetStatusBarColor( this, color );	
	}
	
	// Enables/disables all shell-level navigation (back, path bar)
	private void EnableNavigation( bool enabled )
	{
		AppBar.HasBackButton = enabled && (PageStack.Count > 1);
		PathBar.IsBarEnabled = enabled;
	}
	
	/* Launch */

	// Shows top-level UI in launch stack mode, nothing else visible
	public void ShowLaunch()
	{
		if ( !LaunchStack.IsVisible )
		{
			LaunchStack.IsVisible = true;

			UpdateLayout();
		}
	}

	// Hides launch UI following successful login
	public void HideLaunch()
	{
		if ( LaunchStack.IsVisible )
		{
			AppBar.HasToolBar = true;
			AppBar.HasBackButton = false;
			AppBar.IsVisible = true;

			LaunchStack.IsVisible = false;
		}
	}

	// Hides all main UI components (required on logout)
	public void HideAll()
	{
		HideAppBar();
		HidePageStack();
		
		HideForm();
		HideForm2( null );

		HideRecordForm();
		
		HideDashboardForm();
		HideReportForm();

		HideTool();
	}

	// Hides main UI app bar
	private void HideAppBar()
	{
		if ( AppBar.IsVisible )
		{
			AppBar.IsVisible = false;
		}
	}
	
	/* PageStack */

	// Shows top-level UI in page stack mode
	public void ShowPageStack( bool refresh = true )
	{
		if ( !PageStack.IsVisible )
		{
			AppBar.Title = PageStack.CurrentPage.Title;
			AppBar.Subtitle = null;

			AppBar.HasBackButton = (PageStack.Count > 1);
			AppBar.IsVisible = true;

			PathBar.IsVisible = true;
			PageStack.IsVisible = true;

			if ( refresh )
			{
				PageStack.Refresh();
			}

			UpdateLayout();
		}
	}

	// Hides page stack mode
	private void HidePageStack()
	{
		if ( PageStack.IsVisible )
		{
			PageStack.IsVisible = false;
			PathBar.IsVisible = false;
		}
	}

	/* Forms */
	
	// Determines if any data or analyze form is currently displayed
	public bool IsFormVisible()
	{
		return dataForm.IsVisible || dataForm2.IsVisible || DashboardForm.IsVisible || ReportForm.IsVisible;
	}

	// Shows specified create/edit form
	public void ShowForm( DXContent form )
	{
		if ( !dataForm.IsVisible )
		{
			// Already sized
			dataForm.Content = form;

			// Add on top of all
			Layout.Add( dataForm );

			dataForm.IsVisible = true;

			// Disable navigation items
			EnableNavigation( false );

			UpdateLayout();

			DXSpinner.Stop();
		}
	}

    // Shows secondary data form layer on top of first data form
    public void ShowForm2( DXContent form )
    {
        if ( !dataForm2.IsVisible )
        {
            // Already sized
            dataForm2.Content = form;

            // Add on top of all
            Layout.Add( dataForm2 );

            dataForm2.IsVisible = true;

            UpdateLayout();
        }
    }

	// Hides topmost data form
	public void HideForm( bool refresh = true )
	{
		// Second layer
		if ( dataForm2.IsVisible )
		{
			HideForm2();
		}
		// First layer
		else
		{
			HideForm1( refresh );
		}
	}

	// Hides topmost data form (used by add selectors)
	public void HideForm( DXModel model )
	{
		// Second layer
        if ( dataForm2.IsVisible )
        {
            HideForm2( model );
        }
		// First layer
        else
        {
            HideForm1();
        }
    }

    // Hides first data form layer only
    private void HideForm1( bool refresh = true )
	{
		if ( dataForm.IsVisible )
		{
			dataForm.IsVisible = false;

			// Update UI
			if ( refresh && PageStack.IsVisible )
			{
				PageStack.Refresh();
			}

            // Cleanup
            ToolBar.RemoveCustom( 1 );
            Layout.Remove( dataForm );

			dataForm.Content = null;

            // Re-enable navigation items
            EnableNavigation( true );

			DXSpinner.Stop();
		}
	}

    // Hides secondary data form layer
    public void HideForm2( DXModel model = null )
    {
        if ( dataForm2.IsVisible )
        {
            dataForm2.IsVisible = false;

			// Notify base form that object added
			if ( model != null )
			{
				string key = model.GetType().Name.ToLower();

				(dataForm.Content as DXForm)?.OnObjectAdded( key, model );
			}

            // Cleanup
            Layout.Remove( dataForm2 );

            dataForm2.Content = null;

			DXSpinner.Stop();
        }
    }

	/* Analyze */

	// Shows analyze dashboard form
	public async Task ShowDashboardForm( string title, bool sync = false )
	{
		if ( !DashboardForm.IsVisible )
		{
			DXSpinner.Start();
	
			// App bar
			AppBar.Title = title;
			AppBar.Subtitle = DashboardForm.Title;
			AppBar.HasBackButton = true;
	
			HidePageStack();

			// Cache all json config (once only)
			await DashboardCache.Instance.Init();
			
			// Display				
			await DashboardForm.Show( sync );
	
			UpdateLayout();
		}
	}
	
	// Hides dashboard form if currently showing
	private void HideDashboardForm( bool show = false )
	{
		if ( DashboardForm.IsVisible )
		{
			DashboardForm.Hide();
	
			// Remove sync from toolbar
			AppBar.ToolBar.RemoveCustom( 1 );
	
			if ( show )
			{
				ShowPageStack();
			}
			else
			{
				AppBar.Subtitle = null;
			}
		}
	}
	
	// Shows analyze reports for current category
	public void ShowReportForm( string title, string subtitle )
	{
		if ( !ReportForm.IsVisible )
		{
			AppBar.Title = title;
			AppBar.Subtitle = subtitle;

			ReportForm.Show();

			UpdateLayout();
		}
	}
	
	// Hides report form if currently showing
	private void HideReportForm( bool show = false )
	{
		if ( ReportForm.IsVisible )
		{
			ReportForm.Hide();

			if ( show )
			{
				// Title does not change
				AppBar.Subtitle = DashboardForm.Title;

				// Reset dashboard card tap states
				DashboardForm.Reset();
			}
			else
			{
				AppBar.Subtitle = null;
			}
		}
	}

	/* Record */

	// Shows record UI when starting or resuming set
	public async Task ShowRecordForm( Set set )
	{
		try
		{
			// Lazily create on first launch, new set, or changed sets
			if ( (RecordForm == null) || set.IsNew || !set.Equals( RecordForm.Set ) )
			{
				// Create engine (Legacy or RallyFlow)
				RecordForm = new RecordForm( IsLegacy );
	
				// Config
				await RecordForm.Init( set );
	
				// Start/resume set
				await RecordForm.Start();
	
				// Must be added on top of all
				Layout.Add( RecordForm );
			}
	
			// Show after start/resume
			if ( !RecordForm.IsVisible )
			{
				RecordForm.IsVisible = true;
	
				AppBar.IsVisible = false;
				PathBar.IsVisible = false;
				PageStack.IsVisible = false;
	
				// Must occur last
				UpdateLayout();
			}
		}
		catch ( Exception ex )
		{
			DXLog.Exception( "shell.record", ex );
		}
	
		// Wait until entire UI updated
		DXSpinner.Stop();
	}
	
	// Hides record UI, shows main UI
	public void HideRecordForm( Set set = null )
	{
		if ( RecordForm is { IsVisible: true } )
		{
			AppBar.IsVisible = true;
			PathBar.IsVisible = true;
			PageStack.IsVisible = true;
	
			// Refresh set page to reflect start/end
			if ( set != null )
			{
				PageStack.Pop();
				PageStack.Push( new SetPage( set.Match ), set.Match.Name );
			}
	
			RecordForm.IsVisible = false;
	
			// MUST do a full refresh here
			UpdateLayout();
		}
	}

	/* Tools */

	// Shows specified tool form
	public async Task ShowTool( ToolForm tool, bool portrait = false )
	{
		DXSpinner.Start( "video.cancel", true, OnToolCancelled );
	
		if ( tool != null )
		{
			CurrentTool = tool;
			
			// Config
			await CurrentTool.Init();

			// Must be added on top of all
			Layout.Add( CurrentTool );

			// Start tool functionality
			await CurrentTool.Start();

			// Show after start/resume
			if ( !CurrentTool.IsVisible )
			{
				// Optionally force orientation
				if ( portrait )
				{
					ForcePortrait = true;
				}

				// Display
				CurrentTool.Show();

				AppBar.IsVisible = false;
				PathBar.IsVisible = false;
				PageStack.IsVisible = false;

				// Must occur last
				UpdateLayout();
			}
		}
	}
	
	// Hides current tool form, shows main UI
	public void HideTool( Set set = null )
	{
		if ( CurrentTool is { IsVisible: true } )
		{
			ForcePortrait = false;

			AppBar.IsVisible = true;
			PathBar.IsVisible = true;
			PageStack.IsVisible = true;

			// Refresh set page to reflect start/end
			if ( set != null )
			{
				PageStack.Pop( true );
				PageStack.Push( new SetPage( set.Match ), set.Match.Name );
			}

			CurrentTool.Hide();

			// MUST do a full refresh here
			UpdateLayout();
		}
	}

	// User cancelled video/sync tool while loading 
	private void OnToolCancelled()
	{
		HideTool();
	}
	
	/* Event Callbacks */
	
	// Handles appbar back button taps
	private void OnBackTapped()
	{
		// Launch flow
		if ( LaunchStack.IsVisible )
		{
			LaunchStack.Pop();
		}
		// Analyze form active
		else if ( ReportForm.IsVisible )
		{
			HideReportForm( true );
		}
		else if ( DashboardForm.IsVisible )
		{
			HideDashboardForm( true );
		}
		// Normal home mode
		else if ( PageStack.IsVisible )
		{
			PageStack.Pop();
		}
	}

	// ANDROID: Device back button tapped
	protected override bool OnBackButtonPressed()
	{
		OnBackTapped();

		return true;
	}

	/* Layout */

	// Allows any special handling for device rotation
	public override void Rotate()
	{
		ToolBar.Rotate();
		
		RecordForm?.Rotate();
		ReportForm.Rotate();
	}

	// (Re)calculates drawing bounds for entire UI stack
	public override void UpdateLayout( LayoutType type )
	{
		DXLog.Debug( "Shell:{0}", type );

		bool ios = DXDevice.IsIOS;
		bool tablet = DXDevice.IsTablet;
		
		Thickness safeArea = DXDevice.SafeArea();

		// Calc fixed dimensions based on child sizes
		double wd = DXDevice.GetScreenWd();
		double ht = DXDevice.GetScreenHt();

		double safeWd = (wd - safeArea.HorizontalThickness);
		double safeX = (ios ? safeArea.Left : 0);

		double safeTop = safeArea.Top;
		double safeBottom = safeArea.Bottom;

		// Component heights 
		double appBarHt = AppBar.ViewHt;
		double pathBarHt = PathBar.ViewHt;

		// AppBar draws behind top safe area
		Layout.SetBounds( AppBar, 0, 0, wd, (safeTop + appBarHt) );

		double pathBarY = (ht - pathBarHt - safeBottom);
		
		double pageY = (safeTop + appBarHt);
		double pageHt = (pathBarY - pageY);

		double launchHt = (pageHt + pathBarHt);

		// Save for global use
		ContentHt = pageHt;
		
		// Launch and Page stacks draw behind bottom safe area
		if ( LaunchStack.IsVisible ) 
		{
			Layout.SetBounds( LaunchStack, safeX, pageY, safeWd, launchHt );
		}

		if ( PageStack.IsVisible )
		{
			Layout.SetBounds( PageStack, safeX, pageY, safeWd, pageHt );
		}

		double formX = tablet ? safeX : 0;
		double formWd = tablet ? safeWd : wd;
		double formHt = (pageHt + pathBarHt + safeBottom);

		// Data forms cover path bar
		if ( dataForm.IsVisible )
		{
			Layout.SetBounds( dataForm, formX, pageY, formWd, formHt );
		}
		if ( dataForm2.IsVisible )
		{
			Layout.SetBounds( dataForm2, formX, pageY, formWd, formHt );
		}
		
		// Path bar draws behind bottom safe area
		if ( PathBar.IsVisible )
		{
			Layout.SetBounds( PathBar, 0, pathBarY, wd, (pathBarHt + safeBottom) );
		}
		
		// Record UI
		if ( RecordForm is { IsVisible: true } )
		{
			Layout.SetBounds( RecordForm, 0, 0, wd, ht );
		}

		// Analyze
		if ( DashboardForm.IsVisible )
		{
			Layout.SetBounds( DashboardForm, formX, pageY, formWd, formHt );
		}
		if ( ReportForm.IsVisible )
		{
			Layout.SetBounds( ReportForm, formX, pageY, formWd, formHt );
		}
		
		// Tool
		if ( CurrentTool is { IsVisible: true } )
		{
			Layout.SetBounds( CurrentTool, 0, 0, wd, ht );
		}
		
		// Update child layouts (last)
		UpdateChildren( type );
	}

	// Only update children if currently visible
	private void UpdateChildren( LayoutType type )
	{
		// Top-level
		if ( AppBar.IsVisible )
		{
			AppBar.UpdateLayout( type );
		}
		if ( LaunchStack.IsVisible )
		{
			LaunchStack.UpdateLayout( type );
		}
		if ( PageStack.IsVisible )
		{
			PageStack.UpdateLayout( type );
		}
		if ( PathBar.IsVisible )
		{
			PathBar.UpdateLayout( type );
		}

		// Overlays
		if ( dataForm.IsVisible )
		{
			(dataForm.Content as DXContent)?.UpdateLayout( type );
		}
		if ( dataForm2.IsVisible )
		{
			(dataForm2.Content as DXContent)?.UpdateLayout( type );
		}
	
		// Record UI
		if ( RecordForm is { IsVisible: true } )
		{
			RecordForm.UpdateLayout( type );
		}
		
		// Analyze
		if ( DashboardForm.IsVisible )
		{
			DashboardForm.UpdateLayout( type );
		}

		if ( ReportForm.IsVisible )
		{
			ReportForm.UpdateLayout( type );
		}
		
		// Tool
		if ( CurrentTool is { IsVisible: true } )
		{
			CurrentTool.UpdateLayout( type );
		}
	}
}

//
