@using System.Net.Http.Headers
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

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

<div class="d-flex w-100 h-100 flex-column">
    <div class="d-flex flex-row justify-content-between w-100 mb-3">
        <MudText Typo="Typo.h5" Class="d-flex align-items-center">Element Models</MudText>
        <div class="d-flex flex-row pe-2">
            <MudTooltip RootClass="d-flex align-items-center" Text="Create" Placement="Placement.Bottom" Color="Color.Primary" Arrow="true">
                <MudIconButton Icon="@Icons.Material.Filled.Add" Variant="Variant.Text" Color="Color.Primary" Size="Size.Small" OnClick="OpenCreateModel"></MudIconButton>
            </MudTooltip>
            <MudTooltip RootClass="d-flex align-items-center" Text="Edit" Placement="Placement.Bottom" Color="Color.Info" Arrow="true">
                <MudIconButton Icon="@Icons.Material.Filled.Edit" Size="Size.Small" Color="Color.Info" OnClick="OpenUpdateElementModel" />
            </MudTooltip>
            <MudTooltip RootClass="d-flex align-items-center" Text="Delete" Placement="Placement.Bottom" Color="Color.Secondary" Arrow="true">
                <MudIconButton Icon="@Icons.Material.Filled.Delete" Size="Size.Small" Color="Color.Secondary" OnClick="DeleteElementModel" />
            </MudTooltip>
        </div>
    </div>
    <div class="d-flex w-100 flex-grow-1 overflow-x-hidden overflow-y-auto">
        <MudTreeView Class="d-flex w-100 h-100 flex-column" T="ElementModelDto" Hover SelectedValueChanged="ModelSelectedChanged" SelectedValue="ElementModelSelected">
            @foreach (var model in ElementModels)
            {
                <MudTreeViewItem Value="@model" CanExpand="false" Style="border-bottom: 0.5px solid rgba(217, 217, 217, 0.5); "
                                 Text="@model.Name" EndText="@($"{model.Width}x{model.Height}")" EndTextTypo="Typo.caption" />
            }
        </MudTreeView>
    </div>
</div>

<MudDialog @bind-Visible="@CreateModelIsVisible" DefaultFocus="DefaultFocus.FirstChild">
    <TitleContent>
        <MudText Typo="Typo.h5">Create Element Model</MudText>
    </TitleContent>
    <DialogContent>
        <div class="d-flex flex-column" style="max-height: 700px; overflow-y: auto">
            <MudTextField Class="my-2"
                          @bind-Value="ElementModelCreateModel.Name" T="string"
                          Label="Name" Required="true" RequiredError="Name is required!"
                          Counter="18" Variant="Variant.Outlined"
                          Validation="@(new Func<string, IEnumerable<string>>(MapEditorHelper.NameValidation))" />
            <div class="d-flex flex-row">
                <MudNumericField Class="me-2" @bind-Value="ElementModelCreateModel.Width" Label="Width" Step="0.1" Min="0" Variant="Variant.Outlined" />
                <MudNumericField Class="ms-2" @bind-Value="ElementModelCreateModel.Height" Label="Height" Step="0.1" Min="0" Variant="Variant.Outlined" />
            </div>
            <div class="d-flex flex-row justify-content-around">
                <div class="d-flex flex-column me-2">
                    <div class="d-flex flex-row align-items-center justify-content-center">
                        <InputFile id="fileElementModelImage1Create" OnChange="ElementModelCreateImage1Changed" accept=".png" hidden />
                        <MudText>Open</MudText>
                        <MudIconButton Variant="Variant.Text" Color="Color.Primary" Icon="@Icons.Material.Filled.CloudUpload" for="fileElementModelImage1Create" HtmlTag="label" />
                    </div>
                    <div class="d-flex">
                        <div class="model-create-item">
                            <img alt="Element Model Image Open" src="@ProjectionImageFilePreview1" style="image-rendering: pixelated;" />
                        </div>
                    </div>
                </div>
                <div class="d-flex flex-column">
                    <div class="d-flex flex-row align-items-center justify-content-center">
                        <InputFile id="fileElementModelImage2Create" OnChange="ElementModelCreateImage2Changed" accept=".png" hidden />
                        <MudText>Close</MudText>
                        <MudIconButton Variant="Variant.Text" Color="Color.Primary" Icon="@Icons.Material.Filled.CloudUpload" for="fileElementModelImage2Create" HtmlTag="label" />
                    </div>
                    <div class="d-flex">
                        <div class="model-create-item">
                            <img alt=" Element Model Image Close" src="@ProjectionImageFilePreview2" style="image-rendering: pixelated;" />
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </DialogContent>
    <DialogActions>
        <MudButton Color="Color.Default" Variant="Variant.Filled" OnClick="(() => CreateModelIsVisible = false)">Cancel</MudButton>
        <MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="CreateElementModel" Disabled="string.IsNullOrEmpty(ElementModelCreateModel.Name)">Create</MudButton>
    </DialogActions>
</MudDialog>

<MudDialog @bind-Visible="@UpdateElementModelVisible" DefaultFocus="DefaultFocus.FirstChild">
    <TitleContent>
        <MudText Typo="Typo.h5">Update Element Model</MudText>
    </TitleContent>
    <DialogContent>
        <div class="d-flex flex-column" style="max-height: 700px; overflow-y: auto">
            <MudTextField Class="my-2"
                          @bind-Value="ElementModelUpdateModel.Name" T="string"
                          Label="Name" Required="true" RequiredError="Name is required!"
                          Counter="18" Variant="Variant.Outlined"
                          Validation="@(new Func<string, IEnumerable<string>>(MapEditorHelper.NameValidation))" />
            <div class="d-flex flex-row">
                <MudNumericField Class="me-2" @bind-Value="ElementModelUpdateModel.Width" Label="Width" Step="0.1" Variant="Variant.Outlined" />
                <MudNumericField Class="ms-2" @bind-Value="ElementModelUpdateModel.Height" Label="Height" Step="0.1" Variant="Variant.Outlined" />
            </div>
        </div>
    </DialogContent>
    <DialogActions>
        <MudButton Color="Color.Default" Variant="Variant.Filled" OnClick="(() => UpdateElementModelVisible = false)">Cancel</MudButton>
        <MudButton Color="Color.Primary" Variant="Variant.Filled" OnClick="UpdateElementModel" Disabled="string.IsNullOrEmpty(ElementModelUpdateModel.Name)">Update</MudButton>
    </DialogActions>
</MudDialog>


@code {
    [Parameter]
    public List<ElementModelDto> ElementModels { get; set; } = [];

    [Parameter]
    public MapInfoDto MapInfo { get; set; } = new();

    [Parameter]
    public EventCallback<ElementModelDto?> ElementModelSelectChanged { get; set; }

    private string? txtSearch { get; set; }

    private bool CreateModelIsVisible;
    private ElementModelCreateModel ElementModelCreateModel = new();
    private IBrowserFile? ElementModelCreateImage1 { get; set; }
    private string? ProjectionImageFilePreview1 { get; set; }
    private IBrowserFile? ElementModelCreateImage2 { get; set; }
    private string? ProjectionImageFilePreview2 { get; set; }

    private ElementModelDto? ElementModelSelected = null;

    private bool UpdateElementModelVisible;
    private ElementModelUpdateModel ElementModelUpdateModel = new();

    private HttpClient Http = default!;
    
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await base.OnAfterRenderAsync(firstRender);
        if (!firstRender) return;

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

    private async Task DeleteElementModel()
    {
        if (ElementModelSelected is null) return;

        var parameters = new DialogParameters<ConfirmDialog>
        {
            { x => x.Content, $"Tất cả các Element thuộc model này cũng sẽ bị xóa! Bạn có chắc chắn muốn xóa element model {ElementModelSelected.Name} đi không?" },
            { x => x.ConfirmText, "Delete" },
            { x => x.Color, Color.Secondary }
        };
        var ConfirmDelete = await Dialog.ShowAsync<ConfirmDialog>("Xoá Element 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)
        {
            var response = await Http.DeleteFromJsonAsync<MessageResult>($"api/ElementModels/{ElementModelSelected.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 elementmodel = ElementModels.FirstOrDefault(m => m.Id == ElementModelSelected.Id);
                if (elementmodel is not null)
                {
                    ElementModels.Remove(elementmodel);
                    await ElementModelSelectChanged.InvokeAsync(null);
                    ElementModelSelected = null;
                    Snackbar.Add($"Xóa element model thành công.", Severity.Success);
                }
                else Snackbar.Add($"Element Model không tồn tại.", Severity.Warning);
            }
            StateHasChanged();
        }
    }

    private void OpenCreateModel()
    {
        ElementModelCreateModel.Name = "";
        ElementModelCreateModel.MapId = MapInfo.Id;
        ProjectionImageFilePreview1 = "/images/Image-not-found.png";
        ProjectionImageFilePreview2 = "/images/Image-not-found.png";
        ElementModelCreateImage1 = null;
        ElementModelCreateImage2 = null;

        CreateModelIsVisible = true;
        StateHasChanged();
    }

    private async Task CreateElementModel()
    {
        try
        {
            if (ElementModelCreateImage1 is null || string.IsNullOrEmpty(ProjectionImageFilePreview1))
            {
                Snackbar.Add("Ảnh model chưa được chọn.", Severity.Warning);
                return;
            }
            if (ElementModelCreateImage2 is null || string.IsNullOrEmpty(ProjectionImageFilePreview2))
            {
                Snackbar.Add("Ảnh model chưa được chọn.", Severity.Warning);
                return;
            }

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

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

            using var content = new MultipartFormDataContent
            {
                { new StringContent(ElementModelCreateModel.MapId.ToString()), nameof(ElementModelCreateModel.MapId) },
                { new StringContent(ElementModelCreateModel.Name ?? String.Empty), nameof(ElementModelCreateModel.Name) },
                { new StringContent(ElementModelCreateModel.Width.ToString()), nameof(ElementModelCreateModel.Width) },
                { new StringContent(ElementModelCreateModel.Height.ToString()), nameof(ElementModelCreateModel.Height) },
            };

            var fileContent1 = new StreamContent(ElementModelCreateImage1.OpenReadStream());
            fileContent1.Headers.ContentType = new MediaTypeHeaderValue(ElementModelCreateImage1.ContentType);
            content.Add(fileContent1, "imageOpen", ElementModelCreateImage1.Name);

            var fileContent2 = new StreamContent(ElementModelCreateImage2.OpenReadStream());
            fileContent2.Headers.ContentType = new MediaTypeHeaderValue(ElementModelCreateImage2.ContentType);
            content.Add(fileContent2, "imageClose", ElementModelCreateImage2.Name);

            var response = await (await Http.PostAsync("api/ElementModels", content)).Content.ReadFromJsonAsync<MessageResult<ElementModelDto>>();
            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 if (response.Data is null) Snackbar.Add("Hệ thống không thể tạo Element model này", Severity.Error);
            else
            {
                ElementModels.Add(response.Data);
                Snackbar.Add($"Tạo Element model {response.Data.Name} thành công.", Severity.Success);
            }

            CreateModelIsVisible = false;
            StateHasChanged();
        }
        catch (AccessTokenNotAvailableException ex)
        {
            ex.Redirect();
            return;
        }
    }

    private async Task ElementModelCreateImage1Changed(InputFileChangeEventArgs e)
    {
        ElementModelCreateImage1 = e.File;
        if (ElementModelCreateImage1 is not null)
        {
            var buffers = new byte[ElementModelCreateImage1.Size];
            var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            await using var fs = new FileStream(path, FileMode.Create);
            await ElementModelCreateImage1.OpenReadStream(ElementModelCreateImage1.Size).CopyToAsync(fs);
            fs.Position = 0;
            await fs.ReadAsync(buffers);
            fs.Close();
            File.Delete(path);

            ProjectionImageFilePreview1 = $"data:{ElementModelCreateImage1.ContentType};base64,{Convert.ToBase64String(buffers)}";
            StateHasChanged();
        }
    }

    private async Task ElementModelCreateImage2Changed(InputFileChangeEventArgs e)
    {
        ElementModelCreateImage2 = e.File;
        if (ElementModelCreateImage2 is not null)
        {
            var buffers = new byte[ElementModelCreateImage2.Size];
            var path = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
            await using var fs = new FileStream(path, FileMode.Create);
            await ElementModelCreateImage2.OpenReadStream(ElementModelCreateImage2.Size).CopyToAsync(fs);
            fs.Position = 0;
            await fs.ReadAsync(buffers);
            fs.Close();
            File.Delete(path);

            ProjectionImageFilePreview2 = $"data:{ElementModelCreateImage2.ContentType};base64,{Convert.ToBase64String(buffers)}";
            StateHasChanged();
        }
    }

    private async Task ModelSelectedChanged(ElementModelDto model)
    {
        ElementModelSelected = model;
        var elModel = await Http.GetFromJsonAsync<MessageResult<ElementModelDto>>($"api/ElementModels/{ElementModelSelected.Id}");
        if (elModel is null) Snackbar.Add("Lỗi giao tiếp với hệ thống", Severity.Error);
        else if (!elModel.IsSuccess) Snackbar.Add($"Có lỗi xảy ra: {elModel.Message}", Severity.Error);
        else await ElementModelSelectChanged.InvokeAsync(elModel.Data);
    }

    private void OpenUpdateElementModel()
    {
        if (ElementModelSelected is null) return;
        ElementModelUpdateModel.Id = ElementModelSelected.Id;
        ElementModelUpdateModel.Name = ElementModelSelected.Name;
        ElementModelUpdateModel.Width = ElementModelSelected.Width;
        ElementModelUpdateModel.Height = ElementModelSelected.Height;
        ElementModelUpdateModel.MapId = ElementModelSelected.MapId;
        ElementModelUpdateModel.Content = ElementModelSelected.Content;

        UpdateElementModelVisible = true;
        StateHasChanged();
    }

    private async Task UpdateElementModel()
    {
        var result = await (await Http.PutAsJsonAsync($"api/ElementModels", new ElementModelUpdateModel()
            {
                Id = ElementModelUpdateModel.Id,
                Name = ElementModelUpdateModel.Name,
                Width = ElementModelUpdateModel.Width,
                Height = ElementModelUpdateModel.Height,
                MapId = ElementModelUpdateModel.MapId,
                Content = ElementModelUpdateModel.Content,
            })).Content.ReadFromJsonAsync<MessageResult<ElementModelDto>>();
        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
        {
            var elementModel = ElementModels.FirstOrDefault(m => m.Id == result.Data.Id);
            if (elementModel is not null)
            {
                elementModel.Name = result.Data.Name;
                elementModel.Width = result.Data.Width;
                elementModel.Height = result.Data.Height;
            }
            Snackbar.Add("Cập nhật thành công", Severity.Success);
        }

        UpdateElementModelVisible = false;
        StateHasChanged();
    }
}
