@page "/navigation-maps/editor/{Id:guid}"
@attribute [Authorize]

@using RobotNet.MapShares.Dtos
@using RobotNet.MapShares.Enums
@using RobotNet.Shares
@using RobotNet.WebApp.Maps.Components.Editor
@using RobotNet.WebApp.Maps.Components.Toolbar

@inject IHttpClientFactory HttpClientFactory
@inject IJSRuntime JSRuntime

<PageTitle>Map Designer</PageTitle>

<div class="d-flex flex-column w-100 h-100 position-relative" @onkeyup:preventDefault @onkeypress:preventDefault @onkeydown:preventDefault>
    <EditorToolbar @ref="@EditorToolbarRef" MapIsActive="@MapIsActive" ShowName="@ShowName" ShowGrid="@ShowGrid" ShowMapSlam="@ShowMapSlam" EditorState="@EditorState"
                   MultiSelectedEdge="@MultiselectedEdge" MultiSelectedNode="@MultiselectedNode" NodesUndoable="@NodesUndoable" ZoneSelected="@ZoneSelected"
                   EditorZoneTypeChanged="((zonetype) => ZoneType = zonetype)"
                   ControlStateClick="ControlStateClick"
                   EditorStateChanged="EditorStateChanged"
                   EditorExtensionChanged="EditorExtensionChanged"
                   AlignStateClick="AlignStateClick" />

    <div class="w-100 flex-grow-1">
        <MapContainer @ref="MapContainerRef" ShowGrid="@ShowGrid" ShowName="@ShowName" ShowMapSlam="ShowMapSlam" EditorState="@EditorState" MapIsActive="@MapIsActive" ZoneType="@ZoneType"
                      MultiselectedEdgeChanged="((value) => MultiselectedEdge = value)" 
                      MultiselectedNodeChanged="((value) => MultiselectedNode = value)"
                      ZoneselectedChanged="((value) => ZoneSelected = value)"
                      NodesUndoableChanged="((value) => NodesUndoable = value)" KeyPress="EditorStateChanged" MapIsChecking="MapIsChecking" />
    </div>

    <div class="d-flex w-100 h-100 position-absolute" style="visibility: @(OverlayIsShow ? "visiable" :"hidden")">
        <div class="d-flex w-100 h-100 position-absolute" style="background-color: #f2f2f2; opacity: 0.5; z-index: 999" />
        <div class="d-flex w-100 h-100 align-items-center justify-content-center position-absolute" style="z-index: 1000">
            <div class="d-flex" style="width: fit-content; height: fit-content;">
                <span style="font-size: 4rem; color: red; font-weight: bold">@OverlayIsStr</span>
            </div>
        </div>
    </div>
</div>

@code {
    [Parameter, EditorRequired]
    public Guid Id { get; set; }

    private EditorToolbar EditorToolbarRef = null!;
    private MapContainer MapContainerRef = null!;

    private bool ShowGrid = true;
    private bool ShowName = true;
    private bool ShowMapSlam = true;
    private bool MapIsActive;
    private bool MultiselectedEdge = false;
    private bool MultiselectedNode = false;
    private bool ZoneSelected = false;
    private bool NodesUndoable = false;
    private EditorState EditorState = EditorState.View;
    private ZoneType ZoneType = ZoneType.Operating;

    private bool OverlayIsShow = false;
    private string OverlayIsStr = "Loading...";
    private HttpClient Http = default!;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (!firstRender) return;

        Http = HttpClientFactory.CreateClient("MapManagerAPI");
        await LoadMap();
    }

    private async Task LoadMap()
    {
        try
        {
            OverlayIsShow = true;
            StateHasChanged();

            var mapDataResult = await Http.GetFromJsonAsync<MessageResult<MapDataDto>>($"api/MapsData/{Id}");
            if (mapDataResult is not null && mapDataResult.Data is not null)
            {
                MapIsActive = mapDataResult.Data.Active;
                await MapContainerRef.LoadMap(mapDataResult.Data);
                OverlayIsShow = false;
            }
            else OverlayIsStr = "Map Not Existed";
            StateHasChanged();
        }
        catch
        {
            OverlayIsStr = "Map Not Existed";
            StateHasChanged();
            return;
        }
    }

    private void EditorExtensionChanged((ControlState state, bool value) extension)
    {
        switch (extension.state)
        {
            case ControlState.ShowName:
                ShowName = extension.value;
                break;
            case ControlState.ShowGrid:
                ShowGrid = extension.value;
                break;
            case ControlState.ShowMapSlam:
                ShowMapSlam = extension.value;
                break;
        }
        StateHasChanged();
    }

    private async Task ControlStateClick(ControlState state)
    {
        switch (state)
        {
            case ControlState.Undo:
                MapContainerRef.UndoEditorBackup();
                break;
            case ControlState.FitScreen:
                await MapContainerRef.ScaleFitContentAsync();
                break;
            case ControlState.Save:
                await MapContainerRef.SaveChanged();
                break;
            case ControlState.ZoomIn:
                await MapContainerRef.ScaleZoom(0.5);
                break;
            case ControlState.ZoomOut:
                await MapContainerRef.ScaleZoom(-0.5);
                break;
            case ControlState.Delete:
                if (EditorState == EditorState.NavigationEdit || EditorState == EditorState.Scaner) await MapContainerRef.DeleteEdge();
                else if (EditorState == EditorState.SettingZone) await MapContainerRef.DeleteZone();
                break;
            case ControlState.CheckMap:
                await MapContainerRef.CheckMap();
                break;
        }
    }

    private async Task EditorStateChanged(EditorState state)
    {
        if (EditorState != state)
        {
            EditorState = state;
            await MapContainerRef.EditStateChange();
            EditorToolbarRef.SetEditorState(state);
            StateHasChanged();
        }
    }

    private async Task AlignStateClick(AlignState state)
    {
        switch (state)
        {
            case AlignState.HorizontalLeft:
                MapContainerRef.HorizontalLeft();
                break;
            case AlignState.HorizontalRight:
                MapContainerRef.HorizontalRight();
                break;
            case AlignState.VerticalTop:
                MapContainerRef.VerticalTop();
                break;
            case AlignState.VerticalBottom:
                MapContainerRef.VerticalBottom();
                break;
            case AlignState.HorizontalCenter:
                MapContainerRef.HorizontalCenter();
                break;
            case AlignState.VerticalCenter:
                MapContainerRef.VerticalCenter();
                break;
            case AlignState.MergeNode:
                await MapContainerRef.MergeNode();
                break;
            case AlignState.SplitNode:
                await MapContainerRef.SplitNode();
                break;
        }
    }

    private void MapIsChecking(bool state)
    {
        if (state)
        {
            OverlayIsShow = true;
            OverlayIsStr = "Map Checking ...";
        }
        else OverlayIsShow = false;
        StateHasChanged();
    }
}
