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

<div class="d-flex flex-row w-100 h-100 overflow-hidden position-relative">
    <div class="actions-list">
        <MudGrid Class="m-2" Justify="Justify.FlexStart" Style="width: 93%">
            @foreach (var action in Actions)
            {
                <MudItem Class="p-0 w-100">
                    <MudButton Class="m-1" Variant="Variant.Filled" Color="Color.Info" OnClick="(() => ActionSelectedChanged(action))" Style="text-transform:none">
                        @action.Name
                    </MudButton>
                </MudItem>
            }
        </MudGrid>
    </div>
    <MudDivider Vertical="true" Style="height: 100%; border: 1px solid gray; opacity: 0.7" />
    <div class="d-flex flex-grow-1 flex-row">
        <div class="d-flex flex-grow-1 m-2 flex-column">
            <MudText Typo="Typo.h5">Action: @ActionSelected?.Name</MudText>
            <div class="d-flex flex-column m-2">
                <MudTextField Class="my-2" T="string" @bind-Value="@VDAActionSelected.ActionId" @bind-Value:after="PreviewAction" Variant="Variant.Outlined" Label="Action Id" Immediate />
                <div class="d-flex flex-row my-2">
                    <MudTextField Class="me-1" T="string" @bind-Value="@VDAActionSelected.ActionType" @bind-Value:after="PreviewAction" Variant="Variant.Outlined" Label="Action Type" Immediate />
                    <MudSelect Class="ms-1" T="string" @bind-Value="@VDAActionSelected.BlockingType" @bind-Value:after="PreviewAction" Label="Blocking Type" AnchorOrigin="Origin.BottomLeft" Variant="Variant.Outlined">
                        <MudSelectItem Value="@BlockingType.NONE.ToString()" />
                        <MudSelectItem Value="@BlockingType.SOFT.ToString()" />
                        <MudSelectItem Value="@BlockingType.HARD.ToString()" />
                    </MudSelect>
                </div>
                <MudTextField Class="my-2" T="string" @bind-Value="@VDAActionSelected.ActionDescription" @bind-Value:after="PreviewAction" Variant="Variant.Outlined" Label="Action Description" Lines="3" MaxLines="3" Immediate />
                <div class="d-flex flex-row my-2">
                    <div class="d-flex flex-column w-50 me-1">
                        <MudTextField T="string" Label="Key" Variant="Variant.Outlined" @bind-Value=ActionParameter.Key />
                        <MudTextField T="string" Label="Value" Variant="Variant.Outlined" @bind-Value=ActionParameter.Value />
                    </div>
                    <div class="d-flex flex-grow-1 justify-content-left ms-3 align-items-center">
                        <div>
                            <MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="AddParamterClick" Disabled="@(ActionSelected == null)">Add Parameter</MudButton>
                        </div>
                    </div>
                </div>
                <div class="flex-grow-1 my-2 position-relative">
                    <MudDataGrid T="ActionParameter" Items="@VDAActionSelected.ActionParameters" EditMode="@DataGridEditMode.Cell" ReadOnly="false" Outlined="true"
                    CommittedItemChanges="@CommittedItemChanges"
                    Bordered="true" Dense="true" EditTrigger="DataGridEditTrigger.OnRowClick" Elevation="0" FixedHeader="true" Height="41vh">
                        <ColGroup>
                            <col style="width: 30px" />
                            <col style="width: 35%" />
                            <col style="width: 35%" />
                            <col />
                        </ColGroup>
                        <Columns>
                            <PropertyColumn Property="x => (Array.IndexOf(VDAActionSelected.ActionParameters, x) + 1)" Title="Nr" Editable="false" Required="false" />
                            <PropertyColumn Property="x => x.Key" Editable="true" Title="Key" />
                            <PropertyColumn Property="x => x.Value" Editable="true" Title="Value" />
                            <TemplateColumn Editable="false">
                                <CellTemplate>
                                    <div class="d-flex justify-content-end">
                                        <MudIconButton Size="@Size.Small" Icon="@Icons.Material.Outlined.Delete" Color="Color.Secondary" Variant="Variant.Filled" OnClick="(() => DeleteParameter(context.Item))" />
                                    </div>
                                </CellTemplate>
                            </TemplateColumn>
                        </Columns>
                    </MudDataGrid>
                </div>
            </div>
        </div>
        <div class="actions-preview">
            <MudPaper Outlined="true" Height="100%" Class="p-2" Style="border: 1px solid black; border-radius: 20px">
                <div>
                    @ActionSelected?.Content
                </div>
            </MudPaper>
        </div>
    </div>

    <MudOverlay Visible="OverlayVisible" DarkBackground="true" Absolute="true">
        <MudProgressCircular Color="Color.Secondary" Indeterminate="true" />
    </MudOverlay>
</div>

<MudDialog @bind-Visible="@CreateActionVisible" DefaultFocus="DefaultFocus.FirstChild">
    <TitleContent>
        <MudText Typo="Typo.h5">Create Action</MudText>
    </TitleContent>
    <DialogContent>
        <MudTextField @bind-Value="ActionCreateModel.Name" T="string" Label="Name" Variant="Variant.Outlined" Required="true" RequiredError="Name is Required!" Validation="@(new Func<string, IEnumerable<string>>(MapEditorHelper.NameValidation))" />
    </DialogContent>
    <DialogActions>
        <MudButton Color="Color.Default" Variant="Variant.Filled" OnClick="(() => CreateActionVisible = false)">Cancel</MudButton>
        <MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="CreateAction" Disabled="string.IsNullOrEmpty(ActionCreateModel.Name)">Create</MudButton>
    </DialogActions>
</MudDialog>

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

    private bool CreateActionVisible = false;

    private ActionCreateModel ActionCreateModel = new();

    private List<ActionDto> Actions = [];
    private ActionDto? ActionSelected = null;
    private readonly ActionModel VDAActionSelected = new();
    private readonly ActionModel VDAActionSelectedReset = new();

    private bool OverlayVisible;
    private ActionParameter ActionParameter = new();
    private HttpClient Http = default!;

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

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

    private async Task LoadAction()
    {
        OverlayVisible = true;
        Actions.Clear();
        var result = await Http.GetFromJsonAsync<IEnumerable<ActionDto>>($"api/Actions/{Id}");

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

        OverlayVisible = false;
        StateHasChanged();
    }

    private async Task CreateAction()
    {
        var nameInvalid = MapEditorHelper.NameValidation(ActionCreateModel.Name);
        if (nameInvalid.Any())
        {
            Snackbar.Add(string.Join(';', nameInvalid), Severity.Error);
            return;
        }
        var actionDefault = new ActionModel()
            {
                ActionId = Guid.NewGuid().ToString(),
                ActionType = ActionCreateModel.Name,
                ActionDescription = "",
                BlockingType = BlockingType.NONE.ToString(),
                ActionParameters = [],
            };
        ActionCreateModel.Content = JsonSerializer.Serialize(actionDefault, JsonOptionExtends.Write);

        var result = await (await Http.PostAsJsonAsync<ActionCreateModel>("api/Actions", ActionCreateModel)).Content.ReadFromJsonAsync<MessageResult<ActionDto>>();

        if (result == 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;
        }
        else if (result.Data is null)
        {
            Snackbar.Add("Không có dữ liệu trả về", Severity.Error);
            return;
        }

        Actions.Add(result.Data);
        if (Actions.Any()) ActionSelectedChanged(Actions.First());
        else ActionSelected = new();

        Snackbar.Add("Tạo Action thành công", Severity.Success);
        CreateActionVisible = false;
        StateHasChanged();
    }

    public async Task DeleteAction()
    {
        if (ActionSelected is null) return;
        var parameters = new DialogParameters<ConfirmDialog>
        {
            { x => x.Content, $"Bạn có chắc chắn muốn xóa Action {ActionSelected.Name} đi không?" },
            { x => x.ConfirmText, "Delete" },
            { x => x.Color, Color.Secondary }
        };
        var ConfirmDelete = await Dialog.ShowAsync<ConfirmDialog>("Xoá Action", 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 deletResult = await Http.DeleteFromJsonAsync<MessageResult>($"api/Actions/{ActionSelected.Id}");

            if (deletResult == null)
            {
                Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
                return;
            }
            else if (!deletResult.IsSuccess)
            {
                Snackbar.Add(deletResult.Message, Severity.Error);
                return;
            }

            var action = Actions.FirstOrDefault(action => action.Id == ActionSelected.Id);
            if (action is not null) Actions.Remove(action);
            if (Actions.Any()) ActionSelectedChanged(Actions.First());
            else
            {
                ActionSelected = null;
                ActionModel actionNew = new();
                SetActionSelectedDto(actionNew);
                SetActionSelectedResetDto(actionNew);
            }

            Snackbar.Add("Xóa Action thành công", Severity.Success);
            StateHasChanged();
        }
    }

    private void ActionSelectedChanged(ActionDto action)
    {
        if (ActionSelected != action)
        {
            ActionSelected = action;
            var vdaAction = JsonSerializer.Deserialize<ActionModel>(ActionSelected.Content, JsonOptionExtends.Read);
            if (vdaAction is not null)
            {
                SetActionSelectedDto(vdaAction);
                SetActionSelectedResetDto(vdaAction);
            }
            StateHasChanged();
        }
    }

    public void ShowCreateAction()
    {
        ActionCreateModel.MapId = Id;
        ActionCreateModel.Content = "";
        CreateActionVisible = true;
        StateHasChanged();
    }

    public void Reset()
    {
        if (ActionSelected is null) return;
        SetActionSelectedDto(VDAActionSelectedReset);
        PreviewAction();
        StateHasChanged();
    }

    public async Task Save()
    {
        if (ActionSelected is null) return;
        if (!ValidateUpdateData(VDAActionSelectedReset, VDAActionSelected))
        {
            Snackbar.Add("Không có sự thay đổi", Severity.Warning);
            return;
        }
        ActionSelected.Content = JsonSerializer.Serialize(VDAActionSelected, JsonOptionExtends.Write);

        var result = await (await Http.PutAsJsonAsync<ActionDto>("api/Actions", ActionSelected)).Content.ReadFromJsonAsync<MessageResult>();

        if (result == 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;
        }

        SetActionSelectedResetDto(VDAActionSelected);
        Snackbar.Add("Cập nhật thành công", Severity.Success);
        StateHasChanged();
    }

    private void PreviewAction()
    {
        if (ActionSelected is null) return;
        ActionSelected.Content = JsonSerializer.Serialize(VDAActionSelected, JsonOptionExtends.Write);
        StateHasChanged();
    }

    private void SetActionSelectedDto(ActionModel dto)
    {
        VDAActionSelected.ActionId = dto.ActionId;
        VDAActionSelected.ActionType = dto.ActionType;
        VDAActionSelected.ActionDescription = dto.ActionDescription;
        VDAActionSelected.BlockingType = dto.BlockingType;
        List<ActionParameter> actionParameters = [];
        foreach (var param in dto.ActionParameters)
        {
            actionParameters.Add(new() { Value = param.Value, Key = param.Key });
        }
        VDAActionSelected.ActionParameters = [..actionParameters];
    }

    private void SetActionSelectedResetDto(ActionModel dto)
    {
        VDAActionSelectedReset.ActionId = dto.ActionId;
        VDAActionSelectedReset.ActionType = dto.ActionType;
        VDAActionSelectedReset.ActionDescription = dto.ActionDescription;
        VDAActionSelectedReset.BlockingType = dto.BlockingType;
        List<ActionParameter> actionParameters = [];
        foreach (var param in dto.ActionParameters)
        {
            actionParameters.Add(new() { Value = param.Value, Key = param.Key });
        }
        VDAActionSelectedReset.ActionParameters = [.. actionParameters];
    }

    private bool ValidateUpdateData(ActionModel old, ActionModel update)
    {
        if (old.ActionId != update.ActionId) return true;
        if (old.ActionType != update.ActionType) return true;
        if (old.ActionDescription != update.ActionDescription) return true;
        if (old.BlockingType != update.BlockingType) return true;
        if (old.ActionParameters.Length != update.ActionParameters.Length) return true;
        foreach (var param in old.ActionParameters)
        {
            if (!update.ActionParameters.Any(a => a.Key == param.Key && a.Value == param.Value)) return true;
        }
        return false;
    }

    private void AddParamterClick()
    {
        if (ActionSelected is null) return;
        if (string.IsNullOrEmpty(ActionParameter.Key))
        {
            Snackbar.Add("Key không được để trống", Severity.Warning);
            return;
        }
        if (string.IsNullOrEmpty(ActionParameter.Value))
        {
            Snackbar.Add("Value không được để trống", Severity.Warning);
            return;
        }

        List<ActionParameter> parameters = [];
        if (VDAActionSelected.ActionParameters is not null && VDAActionSelected.ActionParameters.Any()) parameters.AddRange(VDAActionSelected.ActionParameters.ToList());
        parameters.Add(new()
            {
                Key = ActionParameter.Key,
                Value = ActionParameter.Value
            });
        VDAActionSelected.ActionParameters = [.. parameters];
        PreviewAction();
        ActionParameter.Key = string.Empty;
        ActionParameter.Value = string.Empty;
        StateHasChanged();
    }

    private void CommittedItemChanges(ActionParameter item)
    {
        PreviewAction();
        StateHasChanged();
    }

    private async Task DeleteParameter(ActionParameter item)
    {
        var parameters = new DialogParameters<ConfirmDialog>
        {
            { x => x.Content, "Bạn có chắc chắn muốn xóa paramter đi không?" },
            { x => x.ConfirmText, "Delete" },
            { x => x.Color, Color.Secondary }
        };
        var ConfirmDelete = await Dialog.ShowAsync<ConfirmDialog>("Xoá Paramter", 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)
        {
            List<ActionParameter> actionParameters = [];
            if (VDAActionSelected.ActionParameters is not null && VDAActionSelected.ActionParameters.Any()) actionParameters.AddRange(VDAActionSelected.ActionParameters.ToList());
            if (actionParameters.Any()) actionParameters.Remove(item);
            VDAActionSelected.ActionParameters = [.. actionParameters];

            PreviewAction();
            StateHasChanged();
        }
    }
}
