@implements IDisposable
@inject IJSRuntime JSRuntime
@inject IHttpClientFactory HttpClientFactory
@inject ISnackbar Snackbar

<g>
    @foreach (var edge in Models)
    {
        <Edge Model="edge" DoubleClick="OnEdgeDoubleClick" EditorState="@EditorState" />
    }
    @foreach (var edge in Models)
    {
        <EdgeDirection Model="edge" />
    }
</g>

<MudDialog @bind-Visible="updateEdgeVisible">
    <TitleContent>
        <MudText Typo="Typo.h6">
            Update edge @UpdateModel.Id
        </MudText>
    </TitleContent>
    <DialogContent>
        <div class="d-flex flex-row align-items-center">
            <MudText>
                Length: @SelectModelLength m
            </MudText>
        </div>
        <div class="d-flex flex-row mt-2">
            <div class="d-flex flex-column">
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.ControlPoint1X" Label="Control Point 1 X" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.ControlPoint2X" Label="Control Point 2 X" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudSelect @bind-Value="UpdateModel.DirectionAllowed" Label="Direction Allowed" Variant="Variant.Outlined" AnchorOrigin="Origin.BottomLeft" Margin="Margin.Dense" Dense ReadOnly=@(MapIsActive)>
                        <MudSelectItem Value="@(DirectionAllowed.None)" />
                        <MudSelectItem Value="@(DirectionAllowed.Backward)" />
                        <MudSelectItem Value="@(DirectionAllowed.Forward)" />
                        <MudSelectItem Value="@(DirectionAllowed.Both)" />
                    </MudSelect>
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.AllowedDeviationXy" Label="AllowedDeviationXy" Step="0.01" Min="0" Variant="Variant.Outlined" Margin="Margin.Dense" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.AllowedDeviationTheta" Label="AllowedDeviationTheta" Step="1" Min="0" Max="180" Variant="Variant.Outlined" Margin="Margin.Dense" ReadOnly=@(MapIsActive) />
                </div>
                <div class="d-flex">
                    <MudCheckBox @bind-Value="UpdateModel.RotationAllowed" Label="Rotation Allowed" LabelPlacement="Placement.Start" ReadOnly=@(MapIsActive) UncheckedColor="Color.Default" Color="Color.Success" />
                </div>
            </div>

            <div class="d-flex flex-column ms-2">
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.ControlPoint1Y" Label="Control Point 1 Y" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.ControlPoint2Y" Label="Control Point 2 Y" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.MaxSpeed" Label="Max Speed" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" Min="0" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.MaxRotationSpeed" Label="Max Rotation Speed" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" Min="0" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.MaxHeight" Label="Max Height" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" Min="0" ReadOnly=@(MapIsActive) />
                </div>
                <div class="mb-2">
                    <MudNumericField @bind-Value="UpdateModel.MinHeight" Label="Min Height" Variant="Variant.Outlined" Margin="Margin.Dense" Step="0.1" Min="0" ReadOnly=@(MapIsActive) />
                </div>
            </div>

            <div class="d-flex flex-column ms-2 flex-grow-1">
                <div class="d-flex flex-row mb-2">
                    <MudSelect @bind-Value=ActionSelected Margin="Margin.Dense" T="ActionDto" Label="Action" Variant="Variant.Outlined" Class="w-100" AnchorOrigin="Origin.BottomLeft">
                        @foreach (var action in Actions)
                        {
                            <MudSelectItem Value="@action">@action.Name</MudSelectItem>
                        }
                    </MudSelect>
                    <MudFab Class="ms-2" Color="Color.Secondary" StartIcon="@Icons.Material.Filled.Add" Size="Size.Medium" OnClick="AddAction" />
                </div>
                <div class="paper-action">
                    @foreach (var actionId in UpdateModel.Actions)
                    {
                        <div class="m-1" style="height: fit-content">
                            <MudButton Variant="Variant.Filled" Color="Color.Info" Style="text-transform:none" OnClick="(() => DeleteAction(actionId))">
                                @(Actions.FirstOrDefault(ac => ac.Id == actionId)?.Name)
                            </MudButton>
                        </div>
                    }
                </div>
            </div>
        </div>
    </DialogContent>
    <DialogActions>
        <MudButton OnClick="CancelUpdateEdge" Class="px-10" Variant="Variant.Filled">Cancel</MudButton>
        <MudButton OnClick="UpdateEdge" Variant="Variant.Filled" Color="Color.Primary" Class="px-10" Disabled=@(MapIsActive || EditorState == EditorState.View)>Update</MudButton>
    </DialogActions>
</MudDialog>

@code {
    [Parameter, EditorRequired]
    public MapEdgeModel Models { get; set; } = null!;

    [CascadingParameter]
    protected bool MapIsActive { get; set; }

    [Parameter]
    public EventCallback<EdgeModel?> EdgeSelectedChanged { get; set; }

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

    private EdgeUpdateModel UpdateModel = new();
    private bool updateEdgeVisible;
    private string ActionsText { get; set; } = "";
    private double SelectModelLength;

    private List<ActionDto> Actions = [];
    private ActionDto? ActionSelected = null;
    private HttpClient Http = default!;

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

        Http = HttpClientFactory.CreateClient("MapManagerAPI");
        Models.Changed += StateHasChanged;
        Models.EdgeSelectedChanged += async (model) => await EdgeSelectedChanged.InvokeAsync(model);
    }

    private async Task LoadActionAsync(Guid mapVersionId)
    {
        var result = await Http.GetFromJsonAsync<IEnumerable<ActionDto>>($"api/Actions/{mapVersionId}");

        if (result is not null && result.Any())
        {
            Actions.Clear();
            Actions.AddRange(result);
        }
        if (Actions.Any()) ActionSelected = Actions.First();

        StateHasChanged();
    }

    private void AddAction()
    {
        if (ActionSelected is null) return;
        if (UpdateModel.Actions.Any(action => action == ActionSelected.Id))
        {
            Snackbar.Add("Action đã tồn tại", Severity.Warning);
            return;
        }

        UpdateModel.Actions = [.. UpdateModel.Actions, ActionSelected.Id];
        StateHasChanged();
    }

    private void DeleteAction(Guid actionId)
    {
        UpdateModel.Actions = UpdateModel.Actions.Where(a => actionId != a).ToArray();
        StateHasChanged();
    }

    private async Task OnEdgeDoubleClick(EdgeModel model)
    {
        if (model == null || EditorState != EditorState.NavigationEdit) return;

        await LoadActionAsync(model.MapId);

        UpdateModel.Id = model.Id;
        UpdateModel.ControlPoint1X = model.ControlPoint1X;
        UpdateModel.ControlPoint1Y = model.ControlPoint1Y;
        UpdateModel.ControlPoint2X = model.ControlPoint2X;
        UpdateModel.ControlPoint2Y = model.ControlPoint2Y;
        UpdateModel.DirectionAllowed = model.DirectionAllowed;
        UpdateModel.MaxSpeed = model.MaxSpeed;
        UpdateModel.MaxHeight = model.MaxHeight;
        UpdateModel.MinHeight = model.MinHeight;
        UpdateModel.RotationAllowed = model.RotationAllowed;
        UpdateModel.MaxRotationSpeed = model.MaxRotationSpeed;
        UpdateModel.AllowedDeviationXy = model.AllowedDeviationXy;
        UpdateModel.AllowedDeviationTheta = model.AllowedDeviationTheta;

        UpdateModel.Actions = [];
        var actions = JsonSerializer.Deserialize<Guid[]>(model.Actions);
        if (actions is not null && actions.Length > 0)
        {
            UpdateModel.Actions = [.. actions];
        }

        SelectModelLength = MapEditorHelper.GetEdgeLength(new()
        {
            TrajectoryDegree = model.TrajectoryDegree,
            X1 = model.X1,
            Y1 = model.Y1,
            X2 = model.X2,
            Y2 = model.Y2,
            ControlPoint1X = model.ControlPoint1X,
            ControlPoint1Y = model.ControlPoint1Y,
            ControlPoint2X = model.ControlPoint2X,
            ControlPoint2Y = model.ControlPoint2Y,
        });

        updateEdgeVisible = true;
        StateHasChanged();
    }

    private void CancelUpdateEdge()
    {
        updateEdgeVisible = false;
        StateHasChanged();
    }

    private async Task UpdateEdge()
    {
        var selectedModel = Models.FirstOrDefault(e => e.Id == UpdateModel.Id);

        if (selectedModel == null)
        {
            updateEdgeVisible = false;
            StateHasChanged();
            return;
        }

        var result = await (await Http.PutAsJsonAsync($"api/Edges", UpdateModel)).Content.ReadFromJsonAsync<MessageResult>();
        if (result is null)
        {
            Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
            return;
        }
        else if (!result.IsSuccess)
        {
            Snackbar.Add(result.Message, Severity.Error);
            return;
        }

        selectedModel.UpdateData(UpdateModel);
        updateEdgeVisible = false;
        Snackbar.Add("Cập nhật thành công", Severity.Success);
        StateHasChanged();
    }
    
    public void Dispose()
    {
        Models.Changed -= StateHasChanged;
        GC.SuppressFinalize(this);
    }
}
