@inject IHttpClientFactory HttpClientFactory
@inject ISnackbar Snackbar
@inject IDialogService Dialog
@inject NavigationManager Nav

<div class="d-flex w-100 h-100 flex-column ps-2">
    <div class="d-flex flex-row justify-content-between w-100 pb-1">
        <MudText Typo="Typo.h5" Class="d-flex align-items-start">Elements</MudText>
        <MudSpacer />
        <MudTextField @bind-Value="txtSearch" Placeholder="Search" Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium"
        Class="mt-0" Variant="Variant.Outlined" Margin="Margin.Dense" TextChanged="TextSearchChanged" />
        <MudTooltip RootClass="d-flex align-items-center" Text="Exit" Placement="Placement.Bottom" Color="Color.Info" Arrow="true">
            <MudIconButton Class="mx-2 mb-1" Icon="@Icons.Material.Filled.KeyboardReturn" Variant="Variant.Filled" Color="Color.Info" OnClick="@(() => Nav.NavigateTo($"/navigation-maps"))"></MudIconButton>
        </MudTooltip>
    </div>
    <div class="d-flex w-100" style="height: 93%">
        <MudTable Class="w-100" T="ElementDto" @ref="Table" Items="@ElementsShow" Dense Hover ReadOnly Striped Elevation="0" FixedHeader="true"
        Height="92%" RowClass="cursor-pointer" ServerData="ReloadData" Loading="@IsLoading"
        RowClassFunc="@SelectedRowClassFunc" OnRowClick="RowClickEvent">
            <HeaderContent>
                <MudTh>Name</MudTh>
                <MudTh>Model</MudTh>
                <MudTh>IsOpen</MudTh>
                <MudTh>OffsetX</MudTh>
                <MudTh>OffsetY</MudTh>
                <MudTh>NodeId</MudTh>
                <MudTh></MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd DataLabel="Name">@context.Name</MudTd>
                <MudTd DataLabel="Model">@context.ModelName</MudTd>
                <MudTd DataLabel="IsOpen">@context.IsOpen</MudTd>
                <MudTd DataLabel="OffsetX">@context.OffsetX</MudTd>
                <MudTd DataLabel="OffsetY">@context.OffsetY</MudTd>
                <MudTd DataLabel="Node">@context.NodeId</MudTd>
                <MudTd>
                    <div class="d-flex flex-row-reverse">
                        <MudMenu Icon="@Icons.Material.Filled.MoreVert" AnchorOrigin="Origin.BottomCenter">
                            <MudMenuItem OnClick="(() => OpenEditElement(context))" Icon="@Icons.Material.Filled.Edit" IconColor="Color.Info">Edit</MudMenuItem>
                            <MudMenuItem OnClick="(async () => await Delete(context))" Icon="@Icons.Material.Filled.Delete" IconColor="Color.Error">Delete</MudMenuItem>
                        </MudMenu>
                    </div>
                </MudTd>
            </RowTemplate>
            <PagerContent>
                <MudTablePager />
            </PagerContent>
        </MudTable>
    </div>
</div>

<style>
    .selected {
    background-color: #3399ff !important;
    }

    .selected > td {
    color: white !important;
    }

    .selected > td .mud-input {
    color: white !important;
    }
</style>

<MudDialog @bind-Visible="updateElementVisble">
    <TitleContent>
        <MudText Typo="Typo.h6">
            Update Element @ElementUpdateModel.Name
        </MudText>
    </TitleContent>
    <DialogContent>
        <div class="d-flex flex-column" style="max-height: 700px; overflow-y: auto; width: 300px">
            <MudTextField T="string" Label="Name" @bind-value="ElementUpdateModel.Name" Variant="Variant.Outlined"
            Required="true" RequiredError="Name is required!"
            Validation="@(new Func<string, IEnumerable<string>>(MapEditorHelper.NameValidation))" />
            <MudNumericField T="double" Label="OffsetX" @bind-value="ElementUpdateModel.OffsetX" Variant="Variant.Outlined" Step="0.1" />
            <MudNumericField T="double" Label="OffsetY" @bind-value="ElementUpdateModel.OffsetY" Variant="Variant.Outlined" Step="0.1" />
            <MudCheckBox Size="Size.Small" T="bool" LabelPlacement="Placement.Start" Label="IsOpen" @bind-value="ElementUpdateModel.IsOpen" Color="Color.Success"
            UncheckedColor="Color.Default" />
        </div>
    </DialogContent>
    <DialogActions>
        <MudButton OnClick="(() => updateElementVisble = false)" Class="px-10" Variant="Variant.Filled">Cancel</MudButton>
        <MudButton OnClick="UpdateElement" Variant="Variant.Filled" Color="Color.Primary" Class="px-10">Update</MudButton>
    </DialogActions>
</MudDialog>

@code {
    [Parameter]
    public EventCallback<ElementDto?> ElementSelectChanged { get; set; }

    private List<ElementDto> Elements { get; set; } = [];
    private List<ElementDto> ElementsShow { get; set; } = [];

    private string txtSearch = "";
    private bool IsLoading;
    private MudTable<ElementDto> Table = default!;
    private int selectedRowNumber = -1;

    private bool updateElementVisble;
    private ElementUpdateModel ElementUpdateModel = new();
    private HttpClient Http = default!;

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

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

    private bool FilterFunc(ElementDto element)
    {
        if (string.IsNullOrWhiteSpace(txtSearch))
            return true;
        if (element.Name.Contains(txtSearch, StringComparison.OrdinalIgnoreCase))
            return true;
        return false;
    }

    private Task<TableData<ElementDto>> ReloadData(TableState state, CancellationToken _)
    {
        var robots = new List<ElementDto>();
        ElementsShow.Clear();
        Elements.ForEach(robot =>
        {
            if (FilterFunc(robot)) robots.Add(robot);
        });
        ElementsShow = robots.Skip(state.Page * state.PageSize).Take(state.PageSize).ToList();
        return Task.FromResult(new TableData<ElementDto>() { TotalItems = robots.Count(), Items = ElementsShow });
    }

    private async Task LoadElements(Guid modelId)
    {
        IsLoading = true;
        Elements.Clear();
        StateHasChanged();

        var elements = await Http.GetFromJsonAsync<MessageResult<IEnumerable<ElementDto>>>($"api/Elements/{modelId}");
        if (elements is null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
        else if (!elements.IsSuccess) Snackbar.Add($"Có lỗi xảy ra: {elements.Message}", Severity.Error);
        else if (elements.Data is null || !elements.Data.Any())
        {
            Snackbar.Add("Không có element nào trong model này.", Severity.Warning);
            ElementsShow.Clear();
            Table?.ReloadServerData();
        }
        else
        {
            Elements.AddRange(elements.Data.OrderBy(el => el.Name));
            Table?.ReloadServerData();
        }
        IsLoading = false;
        StateHasChanged();
    }

    public async Task SetData(ElementModelDto? model)
    {
        selectedRowNumber = -1;
        Table.SetSelectedItem(null);
        _ = ElementSelectChanged.InvokeAsync(null);
        if (model is null)
        {
            Elements.Clear();
            await Table.ReloadServerData();
        }
        else await LoadElements(model.Id);
    }

    private void RowClickEvent(TableRowClickEventArgs<ElementDto> tableRowClickEventArgs) { }

    private string SelectedRowClassFunc(ElementDto element, int rowNumber)
    {
        if (selectedRowNumber == rowNumber && Table?.SelectedItem != null && !Table.SelectedItem.Equals(element))
        {
            return string.Empty;
        }
        else if (selectedRowNumber == rowNumber && Table?.SelectedItem != null && Table.SelectedItem.Equals(element))
        {
            return "selected";
        }
        else if (Table?.SelectedItem != null && Table.SelectedItem.Equals(element))
        {
            selectedRowNumber = rowNumber;
            _ = ElementSelectChanged.InvokeAsync(element);
            return "selected";
        }
        else
        {
            return string.Empty;
        }
    }

    private void TextSearchChanged(string text)
    {
        txtSearch = text;
        Table?.ReloadServerData();
    }

    private async Task Delete(ElementDto element)
    {
        var parameters = new DialogParameters<ConfirmDialog>
        {
            { x => x.Content, $"Bạn có chắc chắn muốn xóa element {element.Name} đi không?" },
            { x => x.ConfirmText, "Delete" },
            { x => x.Color, Color.Secondary }
        };
        var ConfirmDelete = await Dialog.ShowAsync<ConfirmDialog>("Xoá Element", parameters);
        var result = await ConfirmDelete.Result;
        if (result is not null && result.Data is not null && bool.TryParse(result.Data.ToString(), out bool data) && data)
        {
            var response = await Http.DeleteFromJsonAsync<MessageResult>($"api/Elements/{element.Id}");
            if (response is null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
            else if (!response.IsSuccess) Snackbar.Add(response.Message ?? "Lỗi chưa xác định.", Severity.Error);
            else
            {
                var elementData = Elements.FirstOrDefault(m => m.Id == element.Id);
                if (elementData is not null)
                {
                    Elements.Remove(elementData);
                    await Table.ReloadServerData();
                    await ElementSelectChanged.InvokeAsync(null);
                    selectedRowNumber = -1;
                    Snackbar.Add($"Xóa element thành công.", Severity.Success);
                }
                else Snackbar.Add($"Element không tồn tại.", Severity.Warning);
            }
            StateHasChanged();
        }
    }

    private void OpenEditElement(ElementDto model)
    {
        ElementUpdateModel.Id = model.Id;
        ElementUpdateModel.Name = model.Name;
        ElementUpdateModel.IsOpen = model.IsOpen;
        ElementUpdateModel.OffsetX = model.OffsetX;
        ElementUpdateModel.OffsetY = model.OffsetY;
        ElementUpdateModel.Content = model.Content;

        updateElementVisble = true;
        StateHasChanged();
    }

    private async Task UpdateElement()
    {
        var selectedElement = Elements.FirstOrDefault(e => e.Id == ElementUpdateModel.Id);
        if (selectedElement is null) return;

        var result = await (await Http.PutAsJsonAsync($"api/Elements", new ElementUpdateModel()
            {
                Id = ElementUpdateModel.Id,
                Name = ElementUpdateModel.Name,
                IsOpen = ElementUpdateModel.IsOpen,
                OffsetX = ElementUpdateModel.OffsetX,
                OffsetY = ElementUpdateModel.OffsetY,
                Content = ElementUpdateModel.Content,
            })).Content.ReadFromJsonAsync<MessageResult<ElementDto>>();
        if (result == null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
        else if (!result.IsSuccess) Snackbar.Add(result.Message, Severity.Error);
        else if (result.Data is null) Snackbar.Add("Lỗi dữ liệu", Severity.Error);
        else
        {
            selectedElement.Name = result.Data.Name;
            selectedElement.OffsetX = result.Data.OffsetX;
            selectedElement.OffsetY = result.Data.OffsetY;
            selectedElement.IsOpen = result.Data.IsOpen;
            Snackbar.Add("Cập nhật thành công", Severity.Success);
        }

        updateElementVisble = false;
        StateHasChanged();
    }

    public void UpdateProperty(ElementDto model)
    {
        var element = Elements.FirstOrDefault(e => e.Id == model.Id);
        if (element is null) return;

        element.Name = model.Name;
        element.OffsetX = model.OffsetX;
        element.OffsetY = model.OffsetY;
        element.IsOpen = model.IsOpen;
        element.Content = model.Content;
        StateHasChanged();
    }
}
