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

using System.Text.Json.Serialization;

namespace DXLib.Video;

/*
 * Video player for playing web-based (YouTube, Vimeo) video within an embedded <iframe> player. Two-way communication
 * occurs between C# and the JavaScript API of the player.
 */
public class DXWebVideo : HybridWebView
{
	/* Events */
	public Action PlayerLoaded { get; set; }
	public Action PlayerReady { get; set; }

	/* Properties */
	public LayoutOptions Horizontal { set => HorizontalOptions = value; }
	public LayoutOptions Vertical { set => VerticalOptions = value; }
	
	/* Constants */

	// Available video hosts
	public const string YouTubeHost = "youtube";
	public const string VimeoHost = "vimeo";

	/* Methods */
	public DXWebVideo()
	{
		BackgroundColor = Colors.Black;
		
		Horizontal = LayoutOptions.Fill;
		Vertical = LayoutOptions.Fill;

		// JavaScript config
		HybridRoot = "Web";
		SetInvokeJavaScriptTarget( this );
	}

	// Post-construction initialization
	public void Init( string host )
	{
		DefaultFile = GetPlayerFile( host );
	}
	
	// Returns local HTML file containing <iframe> and JavaScript for embedded video player
	private static string GetPlayerFile( string host )
	{
		return host switch
		{
			YouTubeHost => "youtube.html",
			VimeoHost => "vimeo.html",
			
			_ => null
		};
	}
	
	/* Event Callbacks */

	// Called back when player API loaded
	public void OnLoaded()
	{
		PlayerLoaded?.Invoke();
	}
	
	// Called back when video queued and ready for playback
	public void OnReady()
	{
		PlayerReady?.Invoke();
	}
	
	/* JavaScript Bridge */

	// Cues video to be played, sets starting offset (ms) 
	public async Task SetVideo( string videoURL, int offset )
	{
		await InvokeJavaScriptAsync( "SetVideo", HybridJSContext.Default.Int32, [videoURL, offset], [HybridJSContext.Default.String, HybridJSContext.Default.Int32] );			
	}

	// Advances to specified playback position (ms)
	public async Task<int> SeekTo( double offset )
	{
		return await InvokeJavaScriptAsync( "SeekTo", HybridJSContext.Default.Int32, [offset], [HybridJSContext.Default.Double] );
	}

	// Returns current video playback position (ms)
	public async Task<double> GetVideoTime()
	{
		return await InvokeJavaScriptAsync( "GetVideoTime", HybridJSContext.Default.Double, [], [] );
	}

	// Stops video playback
	public async Task StopVideo()
	{
		await InvokeJavaScriptAsync( "Stop", HybridJSContext.Default.Int32, [], [] );
	}
	
	// Dynamically sets player view size
	public async Task UpdateSize( double width, double height )
	{
		await InvokeJavaScriptAsync( "SetSize", HybridJSContext.Default.Int32, [ (int)width, (int)height ], [HybridJSContext.Default.Int32, HybridJSContext.Default.Int32] );
	}

	// Determines if video cued and ready for playback
	public async Task<bool> IsCued()
	{
		return await InvokeJavaScriptAsync( "IsCued", HybridJSContext.Default.Boolean, [], [] );
	}
}

// Required for C# <-> JavaScript JSON serialization
[JsonSourceGenerationOptions( WriteIndented=true )]
[JsonSerializable( typeof(double) )]
[JsonSerializable( typeof(int) )]
[JsonSerializable( typeof(string) )]
[JsonSerializable( typeof(bool) )]
internal partial class HybridJSContext : JsonSerializerContext;

//
