@using ByteSizeLib;
@using LANCommander.Services;
@using System.IO.Compression;
@inject ArchiveService ArchiveService;

<MudStack Row="true" Style="max-height: 100%">
    <MudTreeView Items="Directories" Hover="true" @bind-SelectedValue="SelectedDirectory" T="ArchiveDirectory" Style="min-width: 18%">
        <ItemTemplate>
            <MudTreeViewItem Expanded="@context.IsExpanded" Value="@context" Items="@context.Children" Text="@context.Name" T="ArchiveDirectory" OnClick="() => ChangeDirectory(context)"></MudTreeViewItem>
        </ItemTemplate>
    </MudTreeView>

    <MudTable Items="@CurrentPathEntries" Hover="true" Class="flex-grow-1 archive-browser" FixedHeader="true" Elevation="0" Height="calc(100vh - 64px)">
        <HeaderContent>
            <MudTh></MudTh>
            <MudTh>Name</MudTh>
            <MudTh>Size</MudTh>
            <MudTh>Modified</MudTh>
            @if (OnFileSelected.HasDelegate)
            {
                <MudTh></MudTh>
            }
        </HeaderContent>
        <RowTemplate>
            <MudTd><MudIcon Icon="@GetIcon(context)" /></MudTd>
            <MudTd>@GetFileName(context)</MudTd>
            <MudTd>@ByteSize.FromBytes(context.Length)</MudTd>
            <MudTd>@context.LastWriteTime</MudTd>
            @if (OnFileSelected.HasDelegate)
            {
                <MudTd><MudButton Class="select-file-button" Color="Color.Primary" Variant="Variant.Filled" OnClick="() => OnFileSelected.InvokeAsync(context.FullName)">Select</MudButton></MudTd>
            }
        </RowTemplate>
    </MudTable>
</MudStack>

<style>
    .select-file-button {
        opacity: 0;
        transition: .1s opacity;
    }

    .archive-browser tr:hover .select-file-button {
        opacity: 1;
    }
</style>

@code {
    [Parameter] public Guid ArchiveId { get; set; }
    [Parameter] public Guid Archive { get; set; }
    [Parameter] public EventCallback<string> OnFileSelected { get; set; }


    private IEnumerable<ZipArchiveEntry> Entries { get; set; }
    private IEnumerable<ZipArchiveEntry> CurrentPathEntries { get; set; }
    private string CurrentPath { get; set; }
    private HashSet<ArchiveDirectory> Directories { get; set; }
    private ArchiveDirectory SelectedDirectory { get; set; }

    protected override async Task OnInitializedAsync()
    {
        Entries = await ArchiveService.GetContents(ArchiveId);
        Directories = new HashSet<ArchiveDirectory>();

        var root = new ArchiveDirectory()
        {
            Name = "/",
            FullName = "",
            IsExpanded = true
        };

        root.PopulateChildren(Entries);

        Directories.Add(root);

        ChangeDirectory(root);
    }

    private void ChangeDirectory(ArchiveDirectory selectedDirectory)
    {
        if (SelectedDirectory == null)
            SelectedDirectory = selectedDirectory;

        if (SelectedDirectory.FullName == "")
            CurrentPathEntries = Entries.Where(e => !e.FullName.TrimEnd('/').Contains('/'));
        else
            CurrentPathEntries = Entries.Where(e => e.FullName.StartsWith(SelectedDirectory.FullName) && e.FullName != SelectedDirectory.FullName);
    }

    private string GetFileName(ZipArchiveEntry entry)
    {
        if (String.IsNullOrWhiteSpace(entry.Name) && entry.Length == 0)
        {
            return entry.FullName.TrimEnd('/').Split('/').Last();
        }
        else
            return entry.Name;
    }

    private string GetIcon(ZipArchiveEntry entry)
    {
        switch (Path.GetExtension(entry.FullName))
        {
            case "":
                return Icons.Material.Filled.Folder;

            case ".exe":
                return Icons.Material.Filled.Terminal;

            case ".zip":
            case ".rar":
            case ".7z":
            case ".gz":
            case ".tar":
                return Icons.Material.Filled.FolderZip;

            case ".wad":
            case ".pk3":
            case ".pak":
            case ".cab":
                return Icons.Material.Filled.Token;

            case ".txt":
            case ".cfg":
            case ".config":
            case ".ini":
            case ".yml":
            case ".yaml":
            case ".log":
            case ".doc":
            case ".nfo":
                return Icons.Custom.FileFormats.FileDocument;

            case ".bat":
            case ".ps1":
            case ".json":
                return Icons.Custom.FileFormats.FileCode;

            case ".bik":
            case ".avi":
            case ".mov":
            case ".mp4":
            case ".m4v":
            case ".mkv":
            case ".wmv":
            case ".mpg":
            case ".mpeg":
            case ".flv":
                return Icons.Custom.FileFormats.FileVideo;

            case ".dll":
                return Icons.Material.Filled.SettingsApplications;

            case ".scm":
                return Icons.Material.Filled.Map;

            case ".hlp":
                return Icons.Material.Filled.Help;

            case ".png":
            case ".bmp":
            case ".jpeg":
            case ".jpg":
            case ".gif":
                return Icons.Custom.FileFormats.FileImage;

            default:
                return Icons.Material.Filled.InsertDriveFile;
        }
    }

    public class ArchiveDirectory
    {
        public string Name { get; set; }
        public string FullName { get; set; }
        public bool IsExpanded { get; set; } = false;
        public bool HasChildren => Children != null && Children.Count > 0;
        public HashSet<ArchiveDirectory> Children { get; set; } = new HashSet<ArchiveDirectory>();

        public void PopulateChildren(IEnumerable<ZipArchiveEntry> entries)
        {
            var childPaths = entries.Where(e => e.FullName.StartsWith(FullName) && e.FullName.EndsWith('/'));
            var directChildren = childPaths.Where(p => p.FullName != FullName && p.FullName.Substring(FullName.Length + 1).TrimEnd('/').Split('/').Length == 1);

            foreach (var directChild in directChildren)
            {
                var child = new ArchiveDirectory()
                {
                    FullName = directChild.FullName,
                    Name = directChild.FullName.Substring(FullName.Length).TrimEnd('/')
                };

                child.PopulateChildren(entries);

                Children.Add(child);
            }
        }
    }
}
