using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.ComponentModel;
using Microsoft.AspNetCore.Components;

using CommonHelpers.WASM;
using AFXUI;

using BookRegistry.Client.Shared;
using BookRegistry.Client.Pages;

namespace BookRegistry.Client {

//**************************************************************************************************
public abstract partial class APageComponent: AComponent {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public bool IsInitialized { get; private set; }
public bool IsLocked { get; private set; } = true;

public bool IsCurrentPage => GetIsCurrentPage();
public virtual bool IsInVigour =>
   IsCurrentPage && !WasDisposed && !IsEscapeRequested;

[DefaultValue(true)]
protected bool UnlockOnLoad { get; set; } = true;
protected bool DeferredFocusBackground { get; set; }

//--------------------------------------------------------------------------------------------------

public static APageComponent? CurrentPage { get; private set; }
public static int PageCount { get; private set; }

//==================================================================================================

public APageComponent()
: base( true )
{}

//==================================================================================================

protected override bool GetIsCurrentPage() =>
   this == CurrentPage;

protected bool CompletePageLoadingUnlock()
{
   if ( !IsInVigour )
      return false;
   UInputBlocking.Unblock( true );
   IsLocked = false;
   ExclusiveLock.ResetExplicit();
   return true;
}

protected override void OnInitialized() =>
go_nt(()=>{
   PageCount++;
   DebugConsole.Print( $"(++) Page count = {PageCount} (\"{GetType()}\")" );
   CurrentPage = this;
   ExclusiveLock.SetExplicit();
   ExclusiveLock.NeutralizeInstances();
   UInputBlocking.Block( true );
   UInputBlocking.NeutralizeInstances();
   ForeOperation.SetIsInReset();
   SetEscapeRequested();
   base.OnInitialized();
   IsInitialized = true;
   MainLayout.Update();
});

protected virtual void On_AutoFocus()
{}

protected override void OnAfterRender(bool firstRender) =>
go_nt(()=>{try{
   if ( !firstRender || !IsCurrentPage )
   {
   // Default behaviour for repeated rendering or phantom page:
      OnAfterRender_Original( firstRender );
      return;
   }
   ResetEscapeRequested();
   try
   {
      On_Load();
      OnAfterRender_Original( true );
      if ( IsInVigour )
         On_AfterLoad();
   }
   finally
   {
      SetEscapeRequested();
   }
}catch(UEscapeException e){
   throw ProhibitedEscapeException( e, nameof(OnAfterRender) );
}});

bool WaitPages() => !IsCurrentPage || PageCount==1;
// ^ being inside “OnAfterRenderAsync” — causes warning CS8619: Nullability of reference types in value of type 'bool' doesn't match target type 'Task'.
protected override Task OnAfterRenderAsync(bool firstRender) =>
go_nt(async()=>{try{
   if ( !firstRender || !IsCurrentPage )
      goto DEFAULT;
   do
   {
      SetEscapeRequested();
   // Exclusive ops must finish (together with all included operations on corresponded pages)!
   // Otherwise we may have killing page in background, with dead element refs (ElementReference)
   // used for JS-interop. (JavaScript then will receive nulls from such abandoned page.)
   // Above-mentioned is concerning only to careless JS-interoperation.
      bool waiting = false;
      if ( Exclusive.HasOperation )
      {
         waiting = true;
         DebugConsole.PrintOperation( "Waiting for exclusive operation" );
         await Exclusive.WaitOperation_A();
      }
      if ( !WaitPages() )
      {
         waiting = true;
         DebugConsole.PrintOperation( ForeOperation.IsOpen ?
            "Waiting for other pages and foreground operation" :
            "Waiting for other pages" );
         await UCircuit.WaitFor_A( WaitPages );
      }
      if ( ForeOperation.IsOpen )
      {
         UFatalBreakdown.ProcessError(
            "Fore operation is unexpectedly open (\"APageComponent\" wait pages routine)." );
         return;
      }
      if ( waiting )
         DebugConsole.Print( "Waiting has completed." );
      if ( !IsCurrentPage ) goto DEFAULT;
   } while ( PageCount > 1 );
   ForeOperation.SetIsInReset( false );
   UMagistral.LocationChanged();
   ResetEscapeRequested();
   await On_Load_A();
   await OnAfterRenderAsync_Original( true );
   if ( !IsInVigour ) return;
   await On_AfterLoad_A();
   if ( !IsInVigour ) return;
   if ( UnlockOnLoad )
      CompletePageLoadingUnlock();
   if ( IsCurrentPage && !WasDisposed && IsEscapeRequested && PageCount==1 )
      throw new ApplicationException(
         $"Prohibited escape reques during page-loading (the only page in vigour) "+
         $"was encountered in \"{GetType()}.OnAfterRenderAsync\"." );
   if ( DeferredFocusBackground )
      UPage.DeferredFocusBackground();
   On_AutoFocus();
   UApplication.SetAnyPageLoaded();
   if ( this is HomePage )
      UApplication.SetHomePageLoaded();
   return;
DEFAULT:
// Default behaviour for repeated rendering, phantom page etc:
   await OnAfterRenderAsync_Original( firstRender );
}catch(UEscapeException e){
   throw ProhibitedEscapeException( e, nameof(OnAfterRenderAsync) );
}});

// <exception cref="ApplicationException" />
ApplicationException ProhibitedEscapeException(UEscapeException e,string methodName) =>
   new ApplicationException(
      $"Prohibited escape exception during page-loading was caught by "+
      $"\"{GetType()}.{methodName}\".", e );

//--------------------------------------------------------------------------------------------------

/// <exception cref="NotImplementedException" />
protected virtual MessageBox MessageBoxInstance =>
   throw new NotImplementedException(
      "\"MessageBoxInstance\"-property (getter) needs to be overridden (\"APageComponent\")." );

//--------------------------------------------------------------------------------------------------

protected override void OnDispose()
{
   base.OnDispose();
   UPage.ResetCurrentPage();
   PageCount--;
   DebugConsole.Print( $"(--) Page count = {PageCount} (\"{GetType()}\")" );
   UMagistral.ResetPageNameDropdownIcon();
}

//==================================================================================================

internal static void ResetCurrentPage() =>
   CurrentPage = null;

//==================================================================================================

static APageComponent() =>
   UApplication.SpecifyGetCurrentPageCallback(() => CurrentPage);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // APageComponent
//**************************************************************************************************

} // BookRegistry.Client
