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

using DXLib.UI.Alert;
using DXLib.UI.Control;

using DXLib.Log;
using DXLib.Video;
using DXLib.Utils;

namespace iStatVball3;

/*
 * Main entry point to the video sync interface. The interface contains a video player on top with an embedded RallyFlow
 * engine below. This allows stats to be recorded with timestamps synchronized to the current elapsed time of the video
 * player.
 */
public class SyncTool : ToolForm, RecordSync
{
	/* Properties */
	private string FileId => set.Match.Video.FileId;
	
	/* Fields */
	
	// Video
	private readonly DXWebVideo videoPlayer;
	
	private double videoWd;
	private double videoHt;
	
	// RallyFlow
	private readonly RallyEngine engine;
	
	// Timeout handling
	private DXTimer timeoutTimer;

	/* Methods */
	public SyncTool( Set set ) : base( set )
	{
		IsVisible = false;

		// MUST have 0 Padding (tap location)
		
		// Video player
		videoPlayer = new DXWebVideo()
		{
			PlayerLoaded = OnLoaded,
			PlayerReady = OnReady
		};

		layout.Add( videoPlayer );

		// RallyFlow engine
		engine = new RallyEngine( layout, RallyEngine.EngineMode.Sync )
		{
			VideoSync = this,

			PauseTapped = OnPauseTapped
		};
	}

	// Post construction initialization
	public override async Task Init()
	{
		Shell.Instance.SetStatusBarColor( DefaultColor );
		
		string host = set.Match.Video.Host;
		
		// Init video player
		videoPlayer.Init( host );
		
		// Set scope
		await engine.Init( set );
	}

	/* Life Cycle */

	// Begins stat recording at start of each set
	public override async Task Start()
	{
		// Prep RallyFlow
		await engine.Start();

		// Update AFTER engine.Start
		engine.StateMachine.UpdateUI();
		
		// Start timeout timer
		timeoutTimer = DXTimer.Delay( LoadTimeout, async void () =>
		{
			try
			{
				// Must successfully load before timeout
				if ( !await videoPlayer.IsCued() )
				{
					await videoPlayer.StopVideo();
					HandleTimeout();
				}
			}
			catch ( Exception ex )
			{
				DXLog.Exception( "sync.start", ex );
			}
		});
	}

	// Closes sync tool, optionally paused for return
	private async Task Close( bool pause )
	{
		timeoutTimer?.Stop();
		
		// Must manually stop
		await videoPlayer.StopVideo();

		Shell shell = Shell.Instance;
		
		// Return to main UI
		shell.SetStatusBarColor( AppBar.DefaultColor );
		shell.HideTool( pause ? set : null );
	}
	
	/* Video Position */

	// Returns video start point (ms) for recording (offset of last stat, if any)
	private int GetStart()
	{
		int count = set.StatCount;
		
		// Get last stat
		Stat stat = (count > 0) ? set.StatCache[ count - 1 ] : null;
		
		// Return offset
		return stat?.VideoOffset ?? 0;
	}
	
	// Returns current video position (ms) for video sync
	public async Task<int> GetOffset()
	{
		return (int)await videoPlayer.GetVideoTime();
	}

	/* Event Callbacks */
	
	// Player API loaded
	private async void OnLoaded()
	{
		// May need to set initial size here
		await videoPlayer.UpdateSize( videoWd, videoHt );

		int start = GetStart();
		
		// Dynamically set video (starts paused,muted)
		await videoPlayer.SetVideo( FileId, start );
		
		// Required for correct <iframe> sizing
		if ( DXDevice.IsMobile )
		{
			UpdateLayout();
		}
	}
	
	// Player ready for video playback
	private static void OnReady()
	{
		// Nothing to do here
		DXSpinner.Stop();
	}

	// Exiting tool from pause button
	private async void OnPauseTapped()
	{
		await Close( true );
	}

	// Exiting tool after timeout
	protected override async void OnToolClosed()
	{
		await Close( false );
	}

	/* Layout */

	// Redraws all components based on device/orientation
	public override void UpdateLayout( LayoutType type )
	{
		Padding = 0;
		
		// Layout for orientation
		base.UpdateLayout( type );
		
		const LayoutType landscape = LayoutType.Landscape;

		// Update video (force to landscape)
		engine.UpdateLayout( landscape );
	}

	// Landscape (4:3)
	protected override void Landscape()
	{
		DXAlert.ShowNeutral( "video.rally", "video.rally.orient", OnToolClosed );
	}

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

		double wd = DXDevice.GetScreenWd();
		double ht = DXDevice.GetScreenHt();

		Thickness safeArea = DXDevice.SafeArea();
		
		// Dynamic sizing
		videoWd = wd;
		videoHt = (videoWd * VideoPlayer.RatioHt);
		
		// Video
		double videoY = safeArea.Top;

		layout.SetBounds( videoPlayer, 0, videoY, videoWd, videoHt );
		videoPlayer.IsVisible = true;

		// Engine
		double engineY = (videoY + videoHt);
		double engineHt = (ht - videoHt - videoY);

		engine.SetLayoutBounds( 0, engineY, wd, engineHt );
	}
}

//
