@namespace Oqtane.UI
@inject SiteState ComponentSiteState
@inject IStringLocalizer<ModuleInstance> Localizer
@inject ILogService LoggingService
@inherits ErrorBoundary

<CascadingValue Value="@PageState">
    <CascadingValue Value="@ModuleState">
        @if (CurrentException is null)
        {
            @if (ModuleType != null)
            {
                @if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "top")
                {
                    <ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" />
                }
                @DynamicComponent
                @if (_progressIndicator)
                {
                    <div class="app-progress-indicator"></div>
                }
                @if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "bottom")
                {
                    <ModuleMessage Message="@_messageContent" Type="@_messageType" Parent="@this" />
                }
            }
        }
        else
        {
            @if (!string.IsNullOrEmpty(_error))
            {
                <ModuleMessage Message="@_error" Type="@MessageType.Error" />
            }
        }
    </CascadingValue>
</CascadingValue>

@code {
    // this component is on the interactive side of the render mode boundary
    // it receives state as serializable parameters so that the state can be made available to downstream components

    private Type ModuleType { get; set; }
    RenderFragment DynamicComponent { get; set; }

    private string _messageContent;
    private MessageType _messageType;
    private string _messagePosition;
    private bool _progressIndicator = false;
    private string _error;

    [Parameter]
    public SiteState SiteState { get; set; }

    [Parameter]
    public PageState PageState { get; set; }

    [Parameter]
    public Module ModuleState { get; set; }

    protected override bool ShouldRender()
    {
        return PageState?.RenderId == ModuleState?.RenderId;
    }

    protected override void OnParametersSet()
    {
        _messageContent = "";

        if (ShouldRender())
        {
            if (!string.IsNullOrEmpty(ModuleState.ModuleType))
            {
                ModuleType = Type.GetType(ModuleState.ModuleType);
                if (ModuleType != null)
                {
                    // repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary)
                    ComponentSiteState.Hydrate(SiteState);

                    DynamicComponent = builder =>
                    {
                        builder.OpenComponent(0, ModuleType);
                        builder.AddAttribute(1, "RenderModeBoundary", this);
                        builder.CloseComponent();
                    };
                }
                else
                {
                    // module does not exist with typename specified
                    _messageContent = string.Format(Localizer["Error.Module.InvalidName"], Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0));
                    _messageType = MessageType.Error;
                    _messagePosition = "top";
                }
            }
            else
            {
                _messageContent = string.Format(Localizer["Error.Module.InvalidType"], ModuleState.ModuleDefinitionName);
                _messageType = MessageType.Error;
                _messagePosition = "top";
            }
        }
    }

    public void AddModuleMessage(string message, MessageType type)
    {
        AddModuleMessage(message, type, "top");
    }

    public void AddModuleMessage(string message, MessageType type, string position)
    {
        if(message != _messageContent
            || type != _messageType
            || position != _messagePosition)
        {
            _messageContent = message;
            _messageType = type;
            _messagePosition = position;
            _progressIndicator = false;

            StateHasChanged();
        }
    }

    public void ShowProgressIndicator()
    {
        _progressIndicator = true;
        StateHasChanged();
    }

    public void HideProgressIndicator()
    {
        _progressIndicator = false;
        StateHasChanged();
    }

    public void DismissMessage()
    {
        _messageContent = "";
        StateHasChanged();
    }

    protected override async Task OnErrorAsync(Exception exception)
    {
        // retrieve friendly localized error
        _error = Localizer["Error.Module.Exception"];
        // log error
        string category = GetType().AssemblyQualifiedName;
        string feature = Utilities.GetTypeNameLastSegment(category, 1);
        await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, PageState.User?.UserId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message);
        await base.OnErrorAsync(exception);
        return;
    }

    public new void Recover()
    {
        _error = "";
        base.Recover();
    }
}