@using System.Net;
@using System.Diagnostics;
@using Hangfire;
@using LANCommander.Jobs.Background;
@using Microsoft.EntityFrameworkCore;
@inject HttpClient HttpClient
@inject NavigationManager Navigator
@inject ArchiveService ArchiveService
@inject IMessageService MessageService
@inject IJSRuntime JS

@{
    RenderFragment Footer =
    @<Template>
        <Button OnClick="UploadArchiveJS" Disabled="@(File == null || Uploading)" Type="@ButtonType.Primary">Upload</Button>
        <Button OnClick="Clear" Disabled="File == null || Uploading" Danger>Clear</Button>
        <Button OnClick="Cancel">Cancel</Button>
    </Template>;
}

<Modal Visible="@Visible" Title="Upload Archive" OnOk="UploadArchiveJS" OnCancel="Cancel" Footer="@Footer">
    <Form Model="@Archive" Layout="@FormLayout.Vertical">
        <FormItem Label="Version">
            <Input @bind-Value="@context.Version" /> 
        </FormItem>

        <FormItem Label="Changelog">
            <TextArea @bind-Value="@context.Changelog" MaxLength=500 ShowCount />
        </FormItem>

        <FormItem>
            <Space Direction="DirectionVHType.Horizontal">
                <SpaceItem>
                     <InputFile @ref="FileInput" id="FileInput" OnChange="FileSelected" hidden />
                     <Upload Name="files" FileList="FileList">
                         <label class="ant-btn" for="FileInput">
                             <Icon Type="upload" />
                            @if (File == null)
                            {
                                <Text>Select File</Text>
                            }
                            else
                            {
                                <Text>Change File</Text>
                            }
                        </label>
                     </Upload>
                </SpaceItem>
                <SpaceItem>
                    @if (File != null)
                    {
                        <Text>@File.Name (@ByteSizeLib.ByteSize.FromBytes(File.Size))</Text>
                    }
                </SpaceItem>
            </Space>
        </FormItem>

        <FormItem>
            <Progress Percent="Progress" Status="@CurrentProgressStatus" Class="uploader-progress" />
            <Text Class="uploader-progress-rate"></Text>
        </FormItem>
    </Form>
</Modal>

@code {
    [Parameter] public Guid GameId { get; set; }
    [Parameter] public Guid RedistributableId { get; set; }
    [Parameter] public EventCallback<Guid> OnArchiveUploaded { get; set; }

    Archive Archive;

    InputFile FileInput;
    IBrowserFile File { get; set; }
    List<UploadFileItem> FileList = new List<UploadFileItem>();

    bool IsValid = false;
    bool Visible = false;

    int Progress = 0;
    bool Uploading = false;
    bool Finished = false;
    double Speed = 0;

    string Filename;

    ProgressStatus CurrentProgressStatus {
        get
        {
            if (Finished)
                return ProgressStatus.Success;
            else if (Uploading)
                return ProgressStatus.Active;
            else
                return ProgressStatus.Normal;
        }
    }

    protected override async Task OnInitializedAsync()
    {
        HttpClient.BaseAddress = new Uri(Navigator.BaseUri);
    }

    private void Clear()
    {
        File = null;
    }

    private void Cancel()
    {
        File = null;
        Visible = false;
    }

    private async void FileSelected(InputFileChangeEventArgs args)
    {
        File = args.File;
    }

    public async Task Open(Guid? archiveId = null)
    {
        if (archiveId.HasValue && archiveId != Guid.Empty)
        {
            Archive = await ArchiveService.Get(archiveId.Value);
        }
        else
        {
            Archive = new Archive();

            if (GameId != Guid.Empty)
                Archive.GameId = GameId;
            else if (RedistributableId != Guid.Empty)
                Archive.RedistributableId = RedistributableId;
        }

        Visible = true;

        await InvokeAsync(StateHasChanged);

        var i = 0;

        // Check every 10 seconds to see if the file input is available
        while (i < 20)
        {
            if (FileInput != null)
            {
                if (!String.IsNullOrWhiteSpace(Archive.ObjectKey) && Archive.ObjectKey != Guid.Empty.ToString())
                    await JS.InvokeVoidAsync("Uploader.Init", "FileInput", Archive.ObjectKey.ToString());
                else
                    await JS.InvokeVoidAsync("Uploader.Init", "FileInput", "");

                break;
            }

            i++;
            await Task.Delay(500);
        }
    }

    private async Task UploadArchiveJS()
    {
        Uploading = true;

        var dotNetReference = DotNetObjectReference.Create(this);

        await JS.InvokeVoidAsync("Uploader.Upload", dotNetReference);

        await InvokeAsync(StateHasChanged);
    }

    [JSInvokable]
    public async void OnUploadComplete(string data)
    {
        if (Guid.TryParse(data, out var objectKey))
        {
            Uploading = false;
            Finished = true;

            Archive.ObjectKey = objectKey.ToString();
            Archive.CompressedSize = File.Size;

            if (Archive.Id != Guid.Empty)
                Archive = await ArchiveService.Update(Archive);
            else
                Archive = await ArchiveService.Add(Archive);

            Visible = false;

            await InvokeAsync(StateHasChanged);

            Archive? lastArchive = null;

            var settings = SettingService.GetSettings();

            if (settings.Archives.EnablePatching)
            {
                if (Archive.GameId != Guid.Empty)
                    lastArchive = await ArchiveService.Get(a => a.Id != Archive.Id && a.GameId == Archive.GameId).OrderByDescending(a => a.CreatedOn).FirstOrDefaultAsync();
                else if (Archive.RedistributableId != Guid.Empty)
                    lastArchive = await ArchiveService.Get(a => a.Id != Archive.Id && a.RedistributableId == Archive.RedistributableId).OrderByDescending(a => a.CreatedOn).FirstOrDefaultAsync();

                if (lastArchive != null && settings.Archives.EnablePatching)
                    BackgroundJob.Enqueue<PatchArchiveBackgroundJob>(x => x.Execute(lastArchive.Id, Archive.Id));
            }

            if (OnArchiveUploaded.HasDelegate)
                await OnArchiveUploaded.InvokeAsync(Archive.Id);

            await MessageService.Success("Archive uploaded!");
        }
        else
        {
            Visible = false;

            await InvokeAsync(StateHasChanged);

            await MessageService.Error("Archive failed to upload!");
        }
    }
}
