using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.JSInterop;

using CommonHelpers.WASM;
using AFXUI;

namespace BookRegistry.Client.Shared {

//**************************************************************************************************
public partial class MessageBox: UComponentBase,IDisposable {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected ElementReference?
   LayoutDIV, DialogTextSPAN, AcceptBUTTON,XAcceptBUTTON,CloseBUTTON;
//==================================================================================================

protected ServiceDialogFrame?
   ServiceDialog;

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

public bool IsOpen { get; private set; }

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

public static bool IsDialogOpen => Current!=null && Current.IsOpen;
public static MessageBox? Current { get; private set; }

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

/// <exception cref="ArgumentException" />
protected MessageBoxParams? Parameters
{
   get => _Parameters_;
   set
   {
      var val = value;
      if ( val == null )
         return;

      if ( val.AcceptButtonCaption==null && val.CloseButtonCaption==null )
         throw ERROR( "Neither of main button captions was specified." );
      if ( val.AcceptButtonCaption==null && val.XAcceptButtonCaption!=null )
         throw ERROR(
            "\"XAcceptButtonCaption\"-parameter requires \"AcceptButtonCaption\" "+
            "to be specified." );

      if (( val.FocusAcceptButton && val.FocusXAcceptButton ||
            val.FocusAcceptButton && val.FocusCloseButton ||
            val.FocusXAcceptButton && val.FocusCloseButton ))
         throw ERROR(
            "Neither combination of \"FocusAcceptButton\",\"FocusXAcceptButton\" and "+
            "\"FocusCloseButton\" parameters can be specified." );

      if ( val.AcceptButtonCaption==null && val.XAcceptButtonCaption!=null )
         throw ERROR(
            "\"XAcceptButtonCaption\"-parameter requires \"AcceptButtonCaption\" "+
            "to be specified." );

      if ( val.AllowEnterKeyAuto && val.AcceptButtonCaption==null )
         throw ERROR(
            "\"AllowEnterKeyAuto\"-parameter requires \"AcceptButtonCaption\" to be specified." );
      if ( val.AllowEscapeCancellation && !val.UseCloseIcon )
         throw ERROR(
            "\"AllowEscapeCancellation\"-parameter requires \"UseCloseIcon\" to be specified." );

      if ( val.FocusAcceptButton && val.AcceptButtonCaption==null )
         throw ERROR(
            "\"FocusAcceptButton\"-parameter requires \"AcceptButtonCaption\" "+
            "to be specified." );
      if ( val.FocusXAcceptButton && val.XAcceptButtonCaption==null )
         throw ERROR(
            "\"FocusXAcceptButton\"-parameter requires \"XAcceptButtonCaption\" "+
            "to be specified." );
      if ( val.FocusCloseButton && val.CloseButtonCaption==null )
         throw ERROR(
            "\"FocusCloseButton\"-parameter requires \"CloseButtonCaption\" "+
            "to be specified." );

      static ArgumentException ERROR(string baseMessage) =>
         new ArgumentException( $"{baseMessage} (\"MessageBox\")." );
   }
}

protected string? Title => Parameters?.Title;
protected string? Text => Parameters?.Text;

protected string? ImagePath => Parameters?.ImagePath;

protected string? AcceptButtonCaption => Parameters?.AcceptButtonCaption;
protected string? XAcceptButtonCaption => Parameters?.XAcceptButtonCaption;
protected string? CloseButtonCaption => Parameters?.CloseButtonCaption;

protected bool FocusAcceptButton => Parameters!=null ? Parameters.FocusAcceptButton : false;
protected bool FocusXAcceptButton => Parameters!=null ? Parameters.FocusXAcceptButton : false;
protected bool FocusCloseButton => Parameters!=null ? Parameters.FocusCloseButton : false;

protected bool UseCloseIcon =>
   Parameters!=null ? Parameters.UseCloseIcon : false;
protected bool AllowEnterKeyAuto =>
   Parameters!=null ? Parameters.AllowEnterKeyAuto : false;
protected bool AllowEscapeCancellation =>
   Parameters!=null ? Parameters.AllowEscapeCancellation : false;

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

public bool HasAcceptButton => Parameters?.AcceptButtonCaption!=null;
public bool HasXAcceptButton => Parameters?.XAcceptButtonCaption!=null;
public bool HasCloseButton => Parameters?.CloseButtonCaption!=null;

protected int AcceptButtonTabIdx =>
   HasAcceptButton ? 1 : 0;
protected int XAcceptButtonTabIdx =>
   AcceptButtonTabIdx + (HasXAcceptButton ? 1 : 0);
protected int CloseButtonTabIdx =>
   XAcceptButtonTabIdx + (HasCloseButton ? 1 : 0);

protected string? LayoutDivTabIdx =>
   FocusAcceptButton || FocusXAcceptButton || FocusCloseButton ? null : "-1";

protected string? CloseWindowDivClasses =>
   UseCloseIcon ? null : "disabledRefA";

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

public static bool Accepted(MessageBoxResult mboxResult) =>
   mboxResult == MessageBoxResult.Accepted;

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

/// <exception cref="UEscapeException" />
public async Task<MessageBoxResult> ESC_ShowDialog_A(MessageBoxParams mboxParams)
{
   if ( IsOpen )
      throw new InvalidOperationException(
         "Message box is allready open or has not been closed correctly (\"MessageBox\")." );
   if ( IsEscapeRequested )
      goto ESCAPE;
   UApplication.PageStateHasChanged();
   await Open_A( mboxParams );
   bool escape = false;
   await UCircuit.WaitFor_A(() => POLL_ESCAPE_N_RESULT());
   if ( escape )
      UInputBlocking.Block( true );
   var rslt = _Result_;
   Close();
   if ( !escape )
      return rslt.V();
ESCAPE:
   throw new UEscapeException( GetType(), nameof(ESC_ShowDialog_A) );
   bool POLL_ESCAPE_N_RESULT()
   {
      if ( IsEscapeRequested )
      {
         escape = true;
         return true;
      }
      if ( _Result_.HasValue )
         return true;
      return false;
   }
}

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

/// <exception cref="InvalidOperationException" />
protected void VerifyIsOpen()
{
   if ( !IsOpen )
      throw new InvalidOperationException( "MessageBox-dialog has not been open." );
}

/// <exception cref="InvalidOperationException" />
protected void VerifyNotOpen()
{
   if ( IsOpen )
      throw new InvalidOperationException( "MessageBox-dialog is allready open." );
}

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

protected override void OnAfterRender(bool firstRender) =>
go_nt(()=>{
   base.OnAfterRender( firstRender );
   if ( !IsOpen || _WasRendered_ )
      return;
   UCircuit.ESC_Check( MethodBase.GetCurrentMethod() );
   ModalDialog.Show();
   JS.Invoke( "MessageBox_Prepare" );
   UMagistral.PushModalPopup( this, DialogTextSPAN.V() );
   _WasRendered_ = true;
   BackwardDeferred.Invoke( "wasm_CompleteOpening" );
});

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

void ResetProperties()
{
   IsOpen = _IsCompletelyOpen_ = _WasRendered_ = false;
   _Parameters_ = null;
   _Result_ = null;
}

/// <exception cref="InvalidOperationException" />
async Task Open_A(MessageBoxParams mbp)
{
   await Task.Delay( 1 ); // breath freely (is necessary)
   DoOpen( mbp );
}
/// <exception cref="InvalidOperationException" />
void DoOpen(MessageBoxParams mbp)
{
   VerifyNotOpen();
   UInputBlocking.Block( true );
   ResetProperties();
   _Parameters_ = mbp;
   IsOpen = true;
   Current = this;
   StateHasChanged();
}

bool Close()
{
   if ( !IsOpen )
      return false;
   UMagistral.PopModalPopup( this );
   ModalDialog.Hide();
   ResetProperties();
   Current = null;
   StateHasChanged();
   return true;
}

void DoCompleteOpening()
{
   UInputBlocking.Unblock( true );
   if ( FocusAcceptButton ) AcceptBUTTON.Focus();
   else if ( FocusXAcceptButton ) XAcceptBUTTON.Focus();
   else if ( FocusCloseButton ) CloseBUTTON.Focus();
   else LayoutDIV.Focus();
   _IsCompletelyOpen_ = true;
}

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

protected ServiceDialogFrame? GetServiceDialog() => ServiceDialog;

/// <exception cref="InvalidOperationException" />
protected ServiceDialogFrame ModalDialog =>
   ServiceDialog ?? throw new InvalidOperationException(
      "\"ModalDialog\"-property is not initialized (\"MessageBox\")." );

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

[JSInvokable]
public static void wasm_MessageBox_EnterKeyAutoAttempt()
{
   var curr = Current;
   if ( curr!=null && curr.IsOpen && curr.HasAcceptButton && curr.AllowEnterKeyAuto )
      curr._Result_ = MessageBoxResult.Accepted;
}

[JSInvokable]
public static void wasm_MessageBox_EscapeCancellationAttempt()
{
   var curr = Current;
   if ( curr!=null && curr.IsOpen && curr.UseCloseIcon && curr.AllowEscapeCancellation )
      curr._Result_ = MessageBoxResult.NotAccepted;
}

[JSInvokable]
public static void wasm_CompleteOpening()
{
   var curr = Current;
   if ( curr!=null && curr.IsOpen && !curr._IsCompletelyOpen_ )
      curr.DoCompleteOpening();
}

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

void IDisposable.Dispose() =>
go_nt(()=>{
   Close();
});

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

void AcceptBUTTON_OnClick() =>
go_nt(()=>{
   _Result_ = MessageBoxResult.Accepted;
});
void XAcceptBUTTON_OnClick() =>
go_nt(()=>{
   _Result_ = MessageBoxResult.XAccepted;
});

void CloseBUTTON_OnClick() =>
go_nt(()=>{
   _Result_ = MessageBoxResult.NotAccepted;
});
void CloseWindowA_OnClick() =>
go_nt(()=>{
   _Result_ = MessageBoxResult.NotAccepted;
});

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

MessageBoxParams? _Parameters_;
MessageBoxResult? _Result_;

bool _IsCompletelyOpen_;
bool _WasRendered_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // MessageBox
//**************************************************************************************************

} // BookRegistry.Client.Shared
