@page "/{Owner}/{Name}/tree/{Branch}"
@page "/{Owner}/{Name}/tree/{Branch}/{*Path}"
@inject IRepositoryService RepositoryService
@inject IGitService GitService

<PageTitle>@(repository?.Owner)/@(repository?.Name) - Forge</PageTitle>

@if (repository == null)
{
    <p>Loading...</p>
}
else
{
    <div class="repo-header">
        <h1>
            <a href="/@repository.Owner">@repository.Owner</a> / <a href="/@repository.Owner/@repository.Name"><strong>@repository.Name</strong></a>
        </h1>
    </div>

    <div class="breadcrumb">
        <a href="/@repository.Owner/@repository.Name/tree/@Branch">@Branch</a>
        @foreach (var segment in breadcrumbSegments)
        {
            <span> / </span>
            <a href="/@repository.Owner/@repository.Name/tree/@Branch/@segment.Path">@segment.Name</a>
        }
    </div>

    @if (loading)
    {
        <p>Loading...</p>
    }
    else if (error != null)
    {
        <p class="empty-state">@error</p>
    }
    else if (treeNodes == null || !treeNodes.Any())
    {
        <p class="empty-state">Empty directory</p>
    }
    else
    {
        <table class="file-list">
            <tbody>
                @foreach (var node in treeNodes)
                {
                    <tr>
                        <td class="icon">
                            @if (node.Type == TreeEntryType.Directory)
                            {
                                <span>📁</span>
                            }
                            else
                            {
                                <span>📄</span>
                            }
                        </td>
                        <td class="name">
                            @if (node.Type == TreeEntryType.Directory)
                            {
                                <a href="/@repository.Owner/@repository.Name/tree/@Branch/@node.Path">@node.Name</a>
                            }
                            else
                            {
                                <a href="/@repository.Owner/@repository.Name/blob/@Branch/@node.Path">@node.Name</a>
                            }
                        </td>
                        <td class="size">
                            @if (node.Size.HasValue)
                            {
                                @FormatSize(node.Size.Value)
                            }
                        </td>
                    </tr>
                }
            </tbody>
        </table>
    }
}

@code {
    [Parameter] public string Owner { get; set; } = "";
    [Parameter] public string Name { get; set; } = "";
    [Parameter] public string Branch { get; set; } = "";
    [Parameter] public string Path { get; set; } = "";

    private Repository? repository;
    private IEnumerable<TreeNode>? treeNodes;
    private bool loading = true;
    private string? error;
    private List<(string Path, string Name)> breadcrumbSegments = [];
    private string? lastRouteKey;

    protected override async Task OnParametersSetAsync()
    {
        // Always recompute breadcrumbs from current Path parameter
        breadcrumbSegments = ComputeBreadcrumbSegments(Path);

        var routeKey = $"{Owner}/{Name}:{Branch}:{Path}";
        if (lastRouteKey != routeKey)
        {
            lastRouteKey = routeKey;
            await LoadAsync();
        }
    }

    private async Task LoadAsync()
    {
        loading = true;
        error = null;
        
        if (repository == null || repository.Owner != Owner || repository.Name != Name)
        {
            repository = await RepositoryService.GetByOwnerAndNameAsync(Owner, Name);
        }
        
        if (repository == null)
        {
            loading = false;
            return;
        }

        if (!GitService.RepositoryExists(repository))
        {
            error = "Repository not found on disk";
            loading = false;
            return;
        }

        var branches = await GitService.GetBranchesAsync(repository);
        var branchExists = branches.Any(b => b.Name == Branch);

        if (!branchExists)
        {
            if (!branches.Any())
            {
                error = "This repository is empty. Push some code to get started!";
            }
            else
            {
                var branchList = string.Join(", ", branches.Select(b => b.Name));
                error = $"Branch '{Branch}' not found. Available branches: {branchList}";
            }
        }
        else
        {
            treeNodes = await GitService.GetTreeAsync(repository, Branch, Path);
            if (treeNodes == null && !string.IsNullOrEmpty(Path))
            {
                error = $"Path '{Path}' not found in this branch";
            }
        }
        
        loading = false;
    }

    private static List<(string Path, string Name)> ComputeBreadcrumbSegments(string? path)
    {
        if (string.IsNullOrEmpty(path))
            return [];
        
        var segments = path.Split('/', StringSplitOptions.RemoveEmptyEntries);
        var result = new List<(string Path, string Name)>();
        var accumulated = "";
        
        foreach (var segment in segments)
        {
            accumulated = string.IsNullOrEmpty(accumulated) ? segment : $"{accumulated}/{segment}";
            result.Add((accumulated, segment));
        }
        
        return result;
    }

    private static string FormatSize(long bytes)
    {
        string[] s = { "B", "KB", "MB", "GB" };
        int i = 0;
        double size = bytes;
        while (size >= 1024 && i < s.Length - 1) { size /= 1024; i++; }
        return $"{size:0.#} {s[i]}";
    }
}
An unhandled error has occurred. Reload 🗙