@page "/queue/{queue?}/{pagination:int?}/{status?}"
@inject QueueService                         QueueSvc
@using Iceshrimp.Backend.Core.Database.Tables
@using Iceshrimp.Backend.Core.Extensions
@using Iceshrimp.Backend.Core.Services
@model QueueModel

@{
    ViewData["title"] = $"Queue dashboard - {Model.InstanceName}";
}

@section head {
    <link rel="stylesheet" href="~/css/queue.css"/>
}

@section scripts {
    <script src="~/js/queue.js"></script>
    @if (Model.Queue == null)
    {
        <script src="~/js/queue-index.js"></script>
    }
}

<h1>Queue Dashboard</h1>
<button role="link" data-target="/queue" onclick="navigate(event)">overview</button>
@foreach (var queue in QueueSvc.QueueNames)
{
    //asd
    <button role="link" data-target="/queue/@queue" onclick="navigate(event)">@queue</button>
}
<br/>

@if (Model.Queue == null)
{
    <p>Please pick a queue.</p>

    <form onsubmit="return lookupJob(event)">
        <input type="text" id="lookup" placeholder="Lookup job by id" minlength="36" maxlength="36" class="inline"/>
        <button type="submit">Submit</button>
    </form>

    <h3>Queue status &mdash; <span id="update-status" class="status-delayed">Connecting...</span></h3>
    <table class="auto-table" id="queue-status">
        <thead>
        <th>Name</th>
        @foreach (var status in Enum.GetValues<Job.JobStatus>())
        {
            var name = Enum.GetName(status);
            <th class="justify-right">@name</th>
        }
        </thead>
        <tbody>
        @foreach (var queue in Model.QueueStatuses ?? throw new Exception("Model.QueueStatuses must not be null here"))
        {
            var isScheduled = QueueModel.ScheduledQueues.Contains(queue.Name);
            var scheduled   = isScheduled ? queue.JobCounts[Job.JobStatus.Delayed].ToString() : "-";
            var delayed     = !isScheduled ? queue.JobCounts[Job.JobStatus.Delayed].ToString() : "-";

            <tr>
                <td>
                    <a href="/queue/@queue.Name" class="color-fg">@queue.Name</a>
                </td>
                @foreach (var status in Enum.GetValues<Job.JobStatus>())
                {
                    var name = Enum.GetName(status)!.ToLowerInvariant();
                    if (status == Job.JobStatus.Delayed)
                    {
                        if (!isScheduled)
                        {
                            <td class="justify-right">
                                <a href="/queue/@queue.Name/1/delayed" class="status-@name">@delayed</a>
                            </td>
                        }
                        else
                        {
                            <td class="justify-right status-@name">@delayed</td>
                        }
                    }
                    else if (status == Job.JobStatus.Queued && isScheduled)
                    {
                        <td class="justify-right">
                            (<a href="/queue/@queue.Name/1/delayed" class="status-scheduled">@scheduled</a>)
                            <a href="/queue/@queue.Name/1/queued" class="status-queued">@queue.JobCounts[status]</a>
                        </td>
                    }
                    else
                    {
                        <td class="justify-right">
                            <a href="/queue/@queue.Name/1/@name" class="status-@name">@queue.JobCounts[status]</a>
                        </td>
                    }
                }
            </tr>
        }
        </tbody>
    </table>

    <h3>Recent jobs</h3>
    <table class="auto-table" id="recent-jobs">
        <thead>
        <th class="width0">ID</th>
        <th>Queue</th>
        <th>Status</th>
        <th>Actions</th>
        </thead>
        <tbody>
        @foreach (var job in Model.Jobs)
        {
            await RenderJobAsync(job, true);
        }
        </tbody>
    </table>

    <h3>Top delayed deliver job targets</h3>
    <table class="auto-table" id="top-delayed">
        <thead>
        <th class="width0">Instance</th>
        <th>Count</th>
        </thead>
        <tbody>
        @foreach (var instance in Model.TopDelayed)
        {
            <tr>
                <td>@instance.Host</td>
                <td><i>@instance.Count jobs</i></td>
            </tr>
        }
        </tbody>
    </table>
    @if (Model.TopDelayed is [])
    {
        <i>No delayed jobs found.</i>
    }

    var last        = Model.Jobs.FirstOrDefault();
    var lastUpdated = last != null ? new DateTimeOffset(last.LastUpdatedAt).ToUnixTimeMilliseconds() : 0;

    <div class="display-none" id="last-updated">@lastUpdated</div>
}

else
{
    var delayedStr = QueueModel.ScheduledQueues.Contains(Model.Queue) ? "scheduled" : "delayed";
    if (Model.Filter == null)
    {
        <p>Listing @Model.TotalCount <b>@Model.Queue</b> jobs, out of which <span class="status-running">@Model.RunningCount</span> are <span class="status-running">running</span>, <span class="status-queued">@Model.QueuedCount</span> are <span class="status-queued">queued</span> and <span class="status-@delayedStr">@Model.DelayedCount</span> are <span class="status-@delayedStr">@delayedStr</span>.</p>
    }
    else
    {
        var filterStr = Model.Filter.Value == Job.JobStatus.Delayed && QueueModel.ScheduledQueues.Contains(Model.Queue)
            ? "scheduled"
            : Model.Filter.Value.ToString().ToLowerInvariant();

        <p>
            Listing @Model.TotalCount <span class="status-@filterStr">@filterStr</span> <b>@Model.Queue</b> jobs.
            @if (Model.Filter is Job.JobStatus.Failed)
            {
                <span>Batch retry: <a class="fake-link" onclick="retryAllFailed('@Model.Queue')">all failed</a> / <a class="fake-link" onclick="retryAllOnPage('@Model.Queue')">all on this page</a></span>
            }
        </p>
    }

    <table class="auto-table">
        <thead>
        <th class="width0">ID</th>
        <th>Status</th>
        <th>Actions</th>
        </thead>
        <tbody>
        @foreach (var job in Model.Jobs)
        {
            await RenderJobAsync(job);
        }
        </tbody>
    </table>

    <div class="flex">
        @if (Model.PrevPage != null)
        {
            if (Model.Filter.HasValue)
            {
                <button role="link" data-target="/queue/@Model.Queue/@Model.PrevPage/@Model.Filter.Value.ToString().ToLowerInvariant()" onclick="navigate">❮ Previous page</button>
            }
            else
            {
                <button role="link" data-target="/queue/@Model.Queue/@Model.PrevPage" onclick="navigate(event)">❮ Previous page</button>
            }
        }
        else
        {
            <button disabled>❮ Previous page</button>
        }

        @if (Model.NextPage != null)
        {
            if (Model.Filter.HasValue)
            {
                <button role="link" data-target="/queue/@Model.Queue/@Model.NextPage/@Model.Filter.Value.ToString().ToLowerInvariant()" onclick="navigate(event)">Next page ❯</button>
            }
            else
            {
                <button role="link" data-target="/queue/@Model.Queue/@Model.NextPage" onclick="navigate(event)">Next page ❯</button>
            }
        }
        else
        {
            <button disabled>Next page ❯</button>
        }

        <select onchange="filter('@Model.Queue')" id="filter" class="inline-flex">
            @if (Model.Filter == null)
            {
                <option value="all" selected>All</option>
            }
            else
            {
                <option value="all">All</option>
            }
            @foreach (var status in Enum.GetValues<Job.JobStatus>())
            {
                var statusStr = status == Job.JobStatus.Delayed && QueueModel.ScheduledQueues.Contains(Model.Queue)
                    ? "Scheduled"
                    : status.ToString();

                if (Model.Filter.Equals(status))
                {
                    <option value="@status.ToString().ToLowerInvariant()" selected>@statusStr</option>
                }
                else
                {
                    <option value="@status.ToString().ToLowerInvariant()">@statusStr</option>
                }
            }
        </select>

        <form onsubmit="return lookupJob(event)" class="inline-flex flex-grow">
            <input type="text" id="lookup" placeholder="Lookup job by id" minlength="36" maxlength="36" class="flex-grow"/>
        </form>
    </div>
}

@{
    async Task RenderJobAsync(Job job, bool withQueue = false)
    {
        var id = job.Id.ToStringLower();
        var additional = job.Status switch
        {
            Job.JobStatus.Delayed when job.RetryCount is 0 => $"for {job.DelayedUntil?.ToLocalTime().ToDisplayStringTz() ?? "<unknown>"}",
            // Separated for readability
            Job.JobStatus.Queued    => $"for {job.QueueDuration.ToDurationDisplayString()}",
            Job.JobStatus.Running   => $"for {job.Duration.ToDurationDisplayString()}",
            Job.JobStatus.Delayed   => $"until {job.DelayedUntil?.ToLocalTime().ToDisplayStringTz() ?? "<unknown>"}",
            Job.JobStatus.Completed => $"at {job.FinishedAt?.ToLocalTime().ToDisplayStringTz() ?? "<unknown>"}",
            Job.JobStatus.Failed    => $"at {job.FinishedAt?.ToLocalTime().ToDisplayStringTz() ?? "<unknown>"}",
            _                       => throw new ArgumentOutOfRangeException()
        };

        var classes = Model.Last != null && new DateTimeOffset(job.LastUpdatedAt).ToUnixTimeMilliseconds() > Model.Last
            ? "new-item"
            : "";

        var status = job is { Status: Job.JobStatus.Delayed, RetryCount: 0 } ? "Scheduled" : job.Status.ToString();

        <tr class="@classes">
            @if (withQueue)
            {
                <td class="uuid-abbrev">@id[..8]...@id[24..]</td>
                <td>@job.Queue</td>
            }
            else
            {
                <td class="uuid">@id</td>
            }
            <td class="status-@status.ToLowerInvariant()">
            <b>@status</b> <small>@additional</small>
            <td>
                <a href="/queue/job/@id">View details</a>
            </td>
        </tr>
    }
}