@namespace Oqtane.Modules.Controls
@inherits ModuleControlBase
@inject IFolderService FolderService
@inject IFileService FileService
@inject IStringLocalizer<FileManager> Localizer

@if (_folders != null)
{
    <div id="@Id" class="container-fluid px-0">
        <div class="row">
            <div class="col">
                @if (ShowFolders || FolderId <= 0)
                {
                    <div>
                        <select class="form-control" value="@FolderId" @onchange="(e => FolderChanged(e))">
                            @if (string.IsNullOrEmpty(Folder))
                            {
                                <option value="-1">&lt;@Localizer["Select Folder"]&gt;</option>
                            }
                            @foreach (Folder folder in _folders)
                            {
                                <option value="@(folder.FolderId)">@(new string('-', folder.Level * 2))@(folder.Name)</option>
                            }
                        </select>
                    </div>
                }
                @if (ShowFiles)
                {
                    <div>
                        <select class="form-control" value="@FileId" @onchange="(e => FileChanged(e))">
                            <option value="-1">&lt;@Localizer["Select File"]&gt;</option>
                            @foreach (File file in _files)
                            {
                                <option value="@(file.FileId)">@(file.Name)</option>
                            }
                        </select>
                    </div>
                }
                @if (ShowUpload && _haseditpermission)
                {
                    <div>
                        @if (UploadMultiple)
                        {
                            <input type="file" id="@_fileinputid" name="file" accept="@_filter" multiple />
                        }
                        else
                        {
                            <input type="file" id="@_fileinputid" name="file" accept="@_filter" />
                        }
                        <span id="@_progressinfoid"></span><progress id="@_progressbarid" style="width: 150px; visibility: hidden;"></progress>
                        <span class="float-right">
                            <button type="button" class="btn btn-success" @onclick="UploadFile">@Localizer["Upload"]</button>
                            @if (ShowFiles && GetFileId() != -1)
                            {
                                <button type="button" class="btn btn-danger" @onclick="DeleteFile">@Localizer["Delete"]</button>
                            }
                        </span>
                    </div>
                }
                <ModuleMessage Message="@_message" Type="@_messagetype"></ModuleMessage>
            </div>
            @if (_image != string.Empty)
            {
                <div class="col-auto">
                    @((MarkupString) _image)
                </div>
            }
        </div>
    </div>
}

@code {
    private string _id;
    private List<Folder> _folders;
    private List<File> _files = new List<File>();
    private string _fileinputid = string.Empty;
    private string _progressinfoid = string.Empty;
    private string _progressbarid = string.Empty;
    private string _filter = "*";
    private bool _haseditpermission = false;
    private string _image = string.Empty;
    private string _guid;
    private string _message = string.Empty;
    private MessageType _messagetype;

    [Parameter]
    public string Id { get; set; } // optional - for setting the id of the FileManager component for accessibility

    [Parameter]
    public string Folder { get; set; } // optional - for setting a specific folder by default

    [Parameter]
    public int FolderId { get; set; } = -1; // optional - for setting a specific folderid by default

    [Parameter]
    public bool ShowFiles { get; set; } = true; // optional - for indicating whether a list of files should be displayed - default is true

    [Parameter]
    public bool ShowUpload { get; set; } = true; // optional - for indicating whether a Upload controls should be displayed - default is true

    [Parameter]
    public bool ShowFolders { get; set; } = true; // optional - for indicating whether a list of folders should be displayed - default is true

    [Parameter]
    public int FileId { get; set; } = -1; // optional - for setting a specific file by default

    [Parameter]
    public string Filter { get; set; } // optional - comma delimited list of file types that can be selected or uploaded ie. "jpg,gif"

    [Parameter]
    public bool UploadMultiple { get; set; } = false; // optional - enable multiple file uploads - default false

    protected override async Task OnInitializedAsync()
    {
        if (!string.IsNullOrEmpty(Id))
        {
            _id = Id;
        }

        if (!string.IsNullOrEmpty(Folder))
        {
            _folders = new List<Folder> { new Folder { FolderId = -1, Name = Folder } };
            FolderId = -1;
        }
        else
        {
            _folders = await FolderService.GetFoldersAsync(ModuleState.SiteId);
        }

        if (FileId != -1)
        {
            File file = await FileService.GetFileAsync(FileId);
            if (file != null)
            {
                FolderId = file.FolderId;
            }
            else
            {
                FileId = -1; // file does not exist
            }
        }
        await SetImage();

        if (!string.IsNullOrEmpty(Filter))
        {
            _filter = "." + Filter.Replace(",", ",.");
        }

        await GetFiles();

        // create unique id for component
        _guid = Guid.NewGuid().ToString("N");
        _fileinputid = _guid + "FileInput";
        _progressinfoid = _guid + "ProgressInfo";
        _progressbarid = _guid + "ProgressBar";
    }

    private async Task GetFiles()
    {
        _haseditpermission = false;
        if (!string.IsNullOrEmpty(Folder))
        {
            _haseditpermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Host);
            _files = await FileService.GetFilesAsync(Folder);
        }
        else
        {
            Folder folder = _folders.FirstOrDefault(item => item.FolderId == FolderId);
            if (folder != null)
            {
                _haseditpermission = UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, folder.Permissions);
                _files = await FileService.GetFilesAsync(FolderId);
            }
            else
            {
                _haseditpermission = false;
                _files = new List<File>();
            }
        }
        if (_filter != "*")
        {
            List<File> filtered = new List<File>();
            foreach (File file in _files)
            {
                if (_filter.ToUpper().IndexOf("." + file.Extension.ToUpper()) != -1)
                {
                    filtered.Add(file);
                }
            }
            _files = filtered;
        }
    }

    private async Task FolderChanged(ChangeEventArgs e)
    {
        _message = string.Empty;
        try
        {
            FolderId = int.Parse((string)e.Value);
            await GetFiles();
            FileId = -1;
            _image = string.Empty;
            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Loading Files {Error}", ex.Message);

            _message = Localizer["Error Loading Files"];
            _messagetype = MessageType.Error;
        }
    }

    private async Task FileChanged(ChangeEventArgs e)
    {
        _message = string.Empty;
        FileId = int.Parse((string)e.Value);

        await SetImage();
        StateHasChanged();
    }

    private async Task SetImage()
    {
        _image = string.Empty;
        if (FileId != -1)
        {
            File file = await FileService.GetFileAsync(FileId);
            if (file != null && file.ImageHeight != 0 && file.ImageWidth != 0)
            {
                var maxwidth = 200;
                var maxheight = 200;

                var ratioX = (double)maxwidth / (double)file.ImageWidth;
                var ratioY = (double)maxheight / (double)file.ImageHeight;
                var ratio = ratioX < ratioY ? ratioX : ratioY;

                _image = "<img src=\"" + ContentUrl(FileId) + "\" alt=\"" + file.Name +
                         "\" width=\"" + Convert.ToInt32(file.ImageWidth * ratio).ToString() +
                         "\" height=\"" + Convert.ToInt32(file.ImageHeight * ratio).ToString() + "\" />";
            }
        }
    }

    private async Task UploadFile()
    {
        _message = string.Empty;
        var interop = new Interop(JSRuntime);
        var upload = await interop.GetFiles(_fileinputid);
        if (upload.Length > 0)
        {
            try
            {
                string result;
                if (!string.IsNullOrEmpty(Folder))
                {
                    result = await FileService.UploadFilesAsync(Folder, upload, _guid);
                }
                else
                {
                    result = await FileService.UploadFilesAsync(FolderId, upload, _guid);
                }

                if (result == string.Empty)
                {
                    await logger.LogInformation("File Upload Succeeded {Files}", upload);

                    _message = Localizer["File Upload Succeeded"];
                    _messagetype = MessageType.Success;

                    await GetFiles();

                    if (upload.Length == 1)
                    {
                        var file = _files.Where(item => item.Name == upload[0]).FirstOrDefault();
                        if (file != null)
                        {
                            FileId = file.FileId;
                            await SetImage();
                        }
                    }
                    StateHasChanged();
                }
                else
                {
                    await logger.LogError("File Upload Failed For {Files}", result.Replace(",", ", "));

                    _message = Localizer["File Upload Failed"];
                    _messagetype = MessageType.Error;
                }
            }
            catch (Exception ex)
            {
                await logger.LogError(ex, "File Upload Failed {Error}", ex.Message);

                _message = Localizer["File Upload Failed"];
                _messagetype = MessageType.Error;
            }
        }
        else
        {
            _message = Localizer["You Have Not Selected A File To Upload"];
            _messagetype = MessageType.Warning;
        }
    }

    private async Task DeleteFile()
    {
        _message = string.Empty;
        try
        {
            await FileService.DeleteFileAsync(FileId);
            await logger.LogInformation("File Deleted {File}", FileId);

            _message = Localizer["File Deleted"];
            _messagetype = MessageType.Success;

            await GetFiles();
            FileId = -1;
            await SetImage();
            StateHasChanged();
        }
        catch (Exception ex)
        {
            await logger.LogError(ex, "Error Deleting File {File} {Error}", FileId, ex.Message);

            _message = Localizer["Error Deleting File"];
            _messagetype = MessageType.Error;
        }
    }

    public int GetFileId() => FileId;

}
