using System;
using Microsoft.AspNetCore.Components;

using CommonHelpers.WASM;
using AFXUI;

using BookRegistry.Client.Shared;

namespace BookRegistry.Client {

//**************************************************************************************************
[HSyncOnlyDisposable]
partial class ForeOperation: HDisposable {
//**************************************************************************************************
class SaveFocusParams {
   public bool SaveFocus { get; }
   public ElementReference? Element { get; }
   public SaveFocusParams(bool saveFocus) => SaveFocus = saveFocus;
   public SaveFocusParams(ElementReference? element) => SaveFocus = (Element = element) != null;
} // SaveFocusParams
//**************************************************************************************************

public bool IsActiveInstance => IsValidDisposable;

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

public static bool IsOpen => _Current_ != null;
public static bool IsActive => UBusyState.IsActive;
public static string OperationText => UBusyState.OperationText ?? "";

public static bool IsInReset { get; private set; }

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

public bool SaveFocus
{
   get => _SaveFocus_;
   set => SetSaveFocus( value );
}

public ElementReference? SaveFocusElement
{
   get => _SaveFocusElement_;
   set => SetSaveFocusElement( value );
}

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

public bool SetSaveFocus( bool value = true,
                          bool withSelectRestoring = false )
{
   if ( _SaveFocus_ = value )
      UPage.SaveFocus( withSelectRestoring );
   else
      UPage.ResetSavedFocus();
   return _SaveFocus_;
}
public bool SetSaveFocus( AComponent control,
                          bool withSelectRestoring = false ) =>
   SetSaveFocusElement( control.MainElement, withSelectRestoring );

public bool SetSaveFocusElement( ElementReference? value,
                                 bool withSelectRestoring = false )
{
   if ( _SaveFocus_ = (_SaveFocusElement_ = value) != null )
      UPage.SaveFocus( _SaveFocusElement_, withSelectRestoring );
   else
      UPage.ResetSavedFocus();
   return _SaveFocus_;
}

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

/// <exception cref="InvalidOperationException" />
public ForeOperation(bool allowCancellation=true)
: this( (SaveFocusParams?)null, allowCancellation )
{}

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

/// <exception cref="InvalidOperationException" />
public ForeOperation(string operationText)
: this( (SaveFocusParams?)null, operationText )
{}
/// <exception cref="InvalidOperationException" />
public ForeOperation(string operationTextFmt, params object?[] parameters)
: this( (SaveFocusParams?)null, operationTextFmt, parameters )
{}

/// <exception cref="InvalidOperationException" />
public ForeOperation( bool allowCancellation, string operationText )
: this( (SaveFocusParams?)null, allowCancellation, operationText )
{}
/// <exception cref="InvalidOperationException" />
public ForeOperation( bool allowCancellation,
                      string operationTextFmt, params object?[] parameters )
: this( (SaveFocusParams?)null, allowCancellation, operationTextFmt, parameters )
{}

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

/// <exception cref="InvalidOperationException" />
public static string Text =>
   DoVerifyAccess()._Text_ ?? throw new InvalidOperationException(
      "\"Text\"-property is unavailable because it has not been assigned (\"ForeOperation\")." );

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

/// <exception cref="InvalidOperationException" />
public static void SetText(string operationText) =>
   SetText( true, operationText );
/// <exception cref="InvalidOperationException" />
public static void SetText(bool allowCancellation,string operationText)
{
   var current = DoVerifyAccess();
   if ( current._Text_ != null )
      UBusyState.SetOperationText( operationText, allowCancellation );
   else
      UBusyState.Activate( operationText, allowCancellation );
   current._Text_ = operationText;
   current._AllowCancellation_ = allowCancellation;
}

/// <exception cref="InvalidOperationException" />
public static void SetText( string operationTextFmt, params object?[] parameters ) =>
   SetText( true, operationTextFmt, parameters );
/// <exception cref="InvalidOperationException" />
public static void SetText( bool allowCancellation,
                            string operationTextFmt, params object?[] parameters ) =>
   SetText( allowCancellation, HString.FormatAsText( operationTextFmt, parameters ) );

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

/// <exception cref="InvalidOperationException" />
public static void NotifyOpAbandoned(bool resetBusyState=true)
{
   VerifyAccess();
   UBusyState.NotifyOpAbandoned( resetBusyState );
}

/// <exception cref="InvalidOperationException" />
public static bool Deactivate()
{
   VerifyAccess();
   var rslt = UBusyState.Deactivate();
   UApplication.PageStateHasChanged();
   return rslt;
}

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

/// <exception cref="InvalidOperationException" />
public static bool WasAbandoned_Notify_Deactivate()
{
   VerifyAccess();
   bool abandoned = UCircuit.WasXOpAbandonedOrCancelled;
   if ( abandoned && !IsInReset )
      NotifyOpAbandoned( true );
   else
      Deactivate();
   return abandoned;
}

/// <exception cref="InvalidOperationException" />
public static bool WasAbandoned_Notify_Deactivate(SimpleSIR simpleResult)
{
   if ( simpleResult.HasError )
      SetOperationFailure( simpleResult );
   return WasAbandoned_Notify_Deactivate();
}

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

public static string SetOperationFailure() =>
   UMagistral.SetOperationFailure();
public static string SetOperationFailure(string? errorMessage) =>
   !IsInReset ?
      UMagistral.SetOperationFailure( errorMessage )
      : "Operation has failed.";
public static string SetOperationFailure(SimpleSIR simpleResult) =>
   SetOperationFailure( simpleResult.ErrorMessage );

[HReturnsNull]
public static string? ResetOperationFailure() =>
   UMagistral.ResetOperationFailure();

public static string SetOpFailure_UnexpectedResponse_A() =>
   SetOpFailure_UnexpectedResponse_A( null );
public static string SetOpFailure_UnexpectedResponse_A(string? additionalMessage=null) =>
   SetOperationFailure( MessageBox.UnexpectedDataOrResult_Msg( additionalMessage ) );

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

/// <exception cref="InvalidOperationException" />
public static void CancelRestoreFocus() =>
   DoVerifyAccess().SaveFocus = false;

public static void SetIsInReset(bool value=true) =>
   IsInReset = value;

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

/// <exception cref="InvalidOperationException" />
public static void VerifyAccess() =>
   DoVerifyAccess();

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

/// <exception cref="InvalidOperationException" />
protected override void OnDispose(bool synchronous)
{
   UBusyState.Deactivate();
   UApplication.PageStateHasChanged();
   if ( SaveFocus && !UCircuit.IsEscapeRequested )
      UPage.RestoreFocus();
   _Current_ = null;
}

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

/// <exception cref="InvalidOperationException" />
ForeOperation( SaveFocusParams? focus, bool allowCancellation=true )
{
   VerifyNotOpen();
   ApplySaveFocusParameters( focus );
   _AllowCancellation_ = allowCancellation;
   ValidateDisposable();
   _Current_ = this;
}

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

/// <exception cref="InvalidOperationException" />
ForeOperation( SaveFocusParams? focus, string operationText )
: this( focus, true, operationText )
{}
/// <exception cref="InvalidOperationException" />
ForeOperation( SaveFocusParams? focus, string operationTextFmt, params object?[] parameters )
: this( focus, true, operationTextFmt, parameters )
{}

/// <exception cref="InvalidOperationException" />
ForeOperation( SaveFocusParams? focus, bool allowCancellation, string operationText )
{
   VerifyNotOpen();
   ApplySaveFocusParameters( focus );
   UBusyState.Activate( _Text_ = operationText, _AllowCancellation_ = allowCancellation );
   ValidateDisposable();
   _Current_ = this;
}
/// <exception cref="InvalidOperationException" />
ForeOperation( SaveFocusParams? focus, bool allowCancellation,
               string operationTextFmt, params object?[] parameters )
: this( focus, allowCancellation, HString.FormatAsText( operationTextFmt, parameters ) )
{}

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

void ApplySaveFocusParameters(SaveFocusParams? focus)
{
   if ( focus != null && focus.SaveFocus )
      if ( focus.Element != null )
         SaveFocusElement = focus.Element;
      else
         SaveFocus = true;
}

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

/// <exception cref="InvalidOperationException" />
void VerifyNotOpen()
{
   if ( IsOpen )
      throw new InvalidOperationException(
         "Attempt to open foreground operation when it is allready open (\"ForeOperation\")." );
}

/// <exception cref="InvalidOperationException" />
static ForeOperation DoVerifyAccess()
{
   var current = _Current_;
   if ( current == null )
      throw new InvalidOperationException(
         "Attempt to access foreground operation when it is not open (\"ForeOperation\")." );
   return current;
}

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

string? _Text_;
bool _AllowCancellation_;
bool _SaveFocus_;
ElementReference? _SaveFocusElement_;

static ForeOperation? _Current_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // ForeOperation
//**************************************************************************************************

} // BookRegistry.Client
