@page "/robots"
@attribute [Authorize]
@implements IAsyncDisposable

@using RobotNet.MapShares
@using RobotNet.RobotShares.Dtos
@using RobotNet.Shares
@using RobotNet.WebApp.Clients
@using RobotNet.WebApp.Robots.Components

@inject ISnackbar Snackbar
@inject IDialogService Dialog
@inject IHttpClientFactory HttpFactory
@inject IJSRuntime JSRuntime
@inject NavigationManager NavManager
@inject RobotHubClient RobotHub

<PageTitle>Robot Manager</PageTitle>

<div class="d-flex flex-column overflow-hidden w-100 h-100 p-2">
    <div class="d-flex justify-content-between align-items-center mb-2">
        <MudTextField Value="txtSearch" T="string" Label="Search" Variant="Variant.Outlined" Adornment="Adornment.End" AdornmentIcon="@Icons.Material.Filled.Search"
        AdornmentColor="Color.Secondary" Style="max-width: 550px" TextChanged="TextSearchChanged" />

        <MudButton Class="me-3" Variant="Variant.Filled" Color="Color.Secondary" OnClick="AddSimulation" Size="Size.Large">Simulation</MudButton>
        <MudButton StartIcon="@Icons.Material.Filled.Add" Variant="Variant.Filled" Color="Color.Primary" Size="Size.Large" OnClick="OpenCreateRobot">
            NEW
        </MudButton>
    </div>
    <div class="d-flex" style="height: 92%">
        <MudTable Class="w-100" @ref="Table" T="RobotDto" Items="@RobotsShow" Loading="@IsLoading" Dense Hover FixedHeader ReadOnly Striped RowClass="cursor-pointer"
        ServerData="ReloadData" MultiSelection @bind-SelectedItems="@RobotSelecteds"
        Outlined="true" Height="95%">
            <HeaderContent>
                <MudTh>Name</MudTh>
                <MudTh>Id</MudTh>
                <MudTh>Model</MudTh>
                <MudTh>Map</MudTh>
                <MudTh>NavigationType</MudTh>
                <MudTh>Online</MudTh>
                <MudTh>State</MudTh>
                <MudTh>Pin</MudTh>
                <MudTh></MudTh>
            </HeaderContent>
            <RowTemplate>
                <MudTd DataLabel="Name">@context.Name</MudTd>
                <MudTd DataLabel="Id">@context.RobotId</MudTd>
                <MudTd DataLabel="Model">@context.ModelName</MudTd>
                <MudTd DataLabel="Map">@context.MapName</MudTd>
                <MudTd DataLabel="NavigationType">@context.NavigationType</MudTd>
                <MudTd DataLabel="Online">
                    <MudAvatar Color="@(context.Online ? Color.Success : Color.Default)" Size="Size.Small"></MudAvatar>
                </MudTd>
                <MudTd DataLabel="State">@context.State</MudTd>
                <MudTd DataLabel="Pin">@($"{context.Battery} %")</MudTd>
                <MudTd>
                    <div class="d-flex justify-content-center">
                        <MudIconButton Icon="@Icons.Material.Filled.Delete" aria-label="Delete" Color="Color.Secondary" OnClick="() => DeleteRobot(context)" />
                        <MudIconButton Icon="@Icons.Material.Filled.TrendingFlat" aria-label="Show" Color="Color.Primary" OnClick="@(() =>NavManager.NavigateTo($"/robots/detail/{context.RobotId}"))" />
                    </div>
                </MudTd>
            </RowTemplate>
            <PagerContent>
                <MudTablePager />
            </PagerContent>
        </MudTable>
    </div>
</div>

<MudDialog @bind-Visible="IsCreateRobotVisible">
    <TitleContent>
        <MudText Typo="Typo.h6">
            Create New Robot
        </MudText>
    </TitleContent>
    <DialogContent>
        <MudContainer Class="d-flex flex-column">
            <MudFocusTrap DefaultFocus="DefaultFocus.FirstChild">
                <MudTextField Class="my-2" Variant="Variant.Outlined"
                              @bind-Value="RobotCreate.Name" T="string"
                              Label="Name" Required="true" Validation="@(new Func<string, IEnumerable<string>>(MapEditorHelper.NameValidation))"
                              RequiredError="Robot's' name is required!" Counter="127" />
                <MudTextField Class="my-2" Variant="Variant.Outlined"
                              @bind-Value="RobotCreate.RobotId" T="string"
                              Label="RobotId" Required="true" Validation="@(new Func<string, IEnumerable<string>>(MapEditorHelper.RobotIdValidation))"
                              RequiredError="Robot's' Id is required!" Counter="127" />
                <MudSelect Class="my-2" T="RobotModelDto" Label="Model" AnchorOrigin="Origin.BottomLeft" @bind-Value="RobotModelSelected" Variant="Variant.Outlined">
                    @foreach (var model in ListRobotModels)
                    {
                        <MudSelectItem Value="@model">@model.ModelName</MudSelectItem>
                    }
                </MudSelect>
            </MudFocusTrap>
        </MudContainer>
    </DialogContent>
    <DialogActions>
        <MudButton OnClick="@(() => IsCreateRobotVisible = false)" Variant="Variant.Filled">Cancel</MudButton>
        <MudButton Color="Color.Primary" OnClick="CreateRobot" Variant="Variant.Filled">Create</MudButton>
    </DialogActions>
</MudDialog>

@code {
    private string? txtSearch { get; set; }
    private bool IsLoading { get; set; }

    private MudTable<RobotDto>? Table;
    private readonly List<RobotDto> Robots = new();
    private List<RobotDto> RobotsShow = new();
    private HashSet<RobotDto> RobotSelecteds = [];

    private bool IsCreateRobotVisible { get; set; }
    private readonly RobotCreateModel RobotCreate = new();
    private readonly List<RobotModelDto> ListRobotModels = new();
    private RobotModelDto? RobotModelSelected { get; set; }

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

        await LoadRobots();
        RobotHub.IsOnlineChanged += RobotIsOnlineChanged;
        await RobotHub.StartAsync();
    }

    private void RobotIsOnlineChanged(IEnumerable<RobotOnlineStateDto> robots)
    {
        foreach (var robot in robots)
        {
            var robotDto = Robots.FirstOrDefault(r => r.RobotId == robot.RobotId);
            if (robotDto is null) continue;
            robotDto.Online = robot.IsOnline;
            robotDto.State = robot.State;
            robotDto.Battery = robot.Battery;
        }
        StateHasChanged();
    }

    private async Task LoadRobots()
    {
        IsLoading = true;
        Robots.Clear();
        StateHasChanged();

        using var Http = HttpFactory.CreateClient("RobotManagerAPI");
        var robots = await Http.GetFromJsonAsync<MessageResult<IEnumerable<RobotDto>>>("api/Robots");
        if (robots is null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
        else if (!robots.IsSuccess) Snackbar.Add($"Có lỗi xảy ra: {robots.Message}", Severity.Error);
        else if (robots.Data is null || !robots.Data.Any())
        {
            Snackbar.Add("Không có robot nào", Severity.Warning);
            RobotsShow.Clear();
            Table?.ReloadServerData();
        }
        else
        {
            Robots.AddRange(robots.Data.OrderByDescending(robot => robot.Online));
            Table?.ReloadServerData();
        }
        IsLoading = false;
        StateHasChanged();
    }

    private bool FilterFunc(RobotDto robot)
    {
        if (string.IsNullOrWhiteSpace(txtSearch))
            return true;
        if (robot.Name.Contains(txtSearch, StringComparison.OrdinalIgnoreCase))
            return true;
        if (robot.RobotId.Contains(txtSearch, StringComparison.OrdinalIgnoreCase))
            return true;
        if (robot.ModelName.Contains(txtSearch, StringComparison.OrdinalIgnoreCase))
            return true;
        if (robot.MapName.ToString().Contains(txtSearch, StringComparison.OrdinalIgnoreCase))
            return true;
        if (robot.State.ToString().Contains(txtSearch, StringComparison.OrdinalIgnoreCase))
            return true;
        if (robot.NavigationType.ToString().Contains(txtSearch, StringComparison.OrdinalIgnoreCase))
            return true;
        return false;
    }

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

    private async Task DeleteRobot(RobotDto robot)
    {
        var parameters = new DialogParameters<ConfirmDialog>
        {
            { x => x.Content, "Bạn có chắc chắn muốn xóa robot đi không?" },
            { x => x.ConfirmText, "Delete" },
            { x => x.Color, Color.Secondary }
        };
        var ConfirmDelete = await Dialog.ShowAsync<ConfirmDialog>("Xoá Robot Model", 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)
        {
            using var Http = HttpFactory.CreateClient("RobotManagerAPI");
            var delete = await Http.DeleteFromJsonAsync<MessageResult>($"api/Robots/{robot.RobotId}");
            if (delete is null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
            else if (!delete.IsSuccess) Snackbar.Add($"Có lỗi xảy ra: {delete.Message}", Severity.Error);
            else
            {
                Robots.Remove(robot);
                Snackbar.Add("Xóa robot thành công!", Severity.Success);
                Table?.ReloadServerData();
            }
            StateHasChanged();
        }
    }

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

    private async Task OpenCreateRobot()
    {
        ListRobotModels.Clear();
        using var Http = HttpFactory.CreateClient("RobotManagerAPI");
        var robotmodels = await Http.GetFromJsonAsync<IEnumerable<RobotModelDto>>($"api/RobotModels?txtSearch={txtSearch}");
        if (robotmodels is null || robotmodels.Count() == 0)
        {
            Snackbar.Add("Vui lòng tạo robot model", Severity.Error);
            return;
        }
        else ListRobotModels.AddRange(robotmodels);

        RobotModelSelected = ListRobotModels.First();
        RobotCreate.Name = "";
        RobotCreate.RobotId = "";
        RobotCreate.ModelId = Guid.Empty;
        IsCreateRobotVisible = true;
        StateHasChanged();
    }

    private async Task CreateRobot()
    {
        if (RobotModelSelected is null)
        {
            Snackbar.Add("Hãy chọn robot model!", Severity.Warning);
            return;
        }
        if (string.IsNullOrEmpty(RobotCreate.Name))
        {
            Snackbar.Add("Trường tên không được để trống", Severity.Warning);
            return;
        }

        var nameInvalid = MapEditorHelper.NameChecking(RobotCreate.Name);
        if (!nameInvalid.IsSuccess)
        {
            Snackbar.Add(nameInvalid.returnStr, Severity.Warning);
            return;
        }

        if (string.IsNullOrEmpty(RobotCreate.RobotId))
        {
            Snackbar.Add("Trường RobotId không được để trống", Severity.Warning);
            return;
        }

        RobotCreate.ModelId = RobotModelSelected.Id;

        using var Http = HttpFactory.CreateClient("RobotManagerAPI");
        var create = await (await Http.PostAsJsonAsync("api/Robots", RobotCreate)).Content.ReadFromJsonAsync<MessageResult<RobotDto>>();
        if (create is null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
        else if (!create.IsSuccess) Snackbar.Add($"Có lỗi xảy ra: {create.Message}", Severity.Error);
        else if (create.Data is null) Snackbar.Add("Tạo robot không thành công", Severity.Error);
        else
        {
            Robots.Add(new()
                {
                    Id = create.Data.Id,
                    RobotId = create.Data.RobotId,
                    Name = create.Data.Name,
                    ModelId = create.Data.ModelId,
                    ModelName = create.Data.ModelName,
                    NavigationType = create.Data.NavigationType,
                });
            Table?.ReloadServerData();
            IsCreateRobotVisible = false;
            Snackbar.Add("Tạo robot thành công!", Severity.Success);
        }
        StateHasChanged();
    }

    private async Task AddSimulation()
    {
        if (!RobotSelecteds.Any()) return;
        var robotIds = RobotSelecteds.Select(r => r.RobotId).ToList();

        using var Http = HttpFactory.CreateClient("RobotManagerAPI");
        var onRobot = await (await Http.PostAsJsonAsync($"api/Robots/simulation", robotIds)).Content.ReadFromJsonAsync<MessageResult>();
        if (onRobot is null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
        else if (!onRobot.IsSuccess) Snackbar.Add($"Có lỗi xảy ra: {onRobot.Message}", Severity.Error);
        else Snackbar.Add("Khởi tạo thành công!", Severity.Success);
        StateHasChanged();
    }

    public async ValueTask DisposeAsync()
    {
        RobotHub.IsOnlineChanged -= RobotIsOnlineChanged;
        await RobotHub.StopAsync();
    }
}
