@page "/admin/invites"
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "Admin")]
@rendermode InteractiveServer
@inject InviteService InviteSvc
@inject IDbContextFactory<ApplicationDbContext> DbFactory
@inject AuthenticationStateProvider AuthState

<PageTitle>Admin · Invitations</PageTitle>

<div class="d-flex justify-content-between align-items-center mb-3">
    <h1>Invitations</h1>
    <a class="btn btn-outline-secondary" href="admin/users">Back to users</a>
</div>

<div class="card mb-4">
    <div class="card-body">
        <h5 class="card-title">Invite someone</h5>
        <EditForm Model="form" OnValidSubmit="CreateAsync">
            <DataAnnotationsValidator />
            <div class="row g-2 align-items-end">
                <div class="col-md-6">
                    <label class="form-label">Email</label>
                    <InputText class="form-control" @bind-Value="form.Email" placeholder="name@example.com" />
                    <ValidationMessage For="() => form.Email" />
                </div>
                <div class="col-md-3">
                    <label class="form-label">Role</label>
                    <InputSelect class="form-select" @bind-Value="form.Role">
                        <option value="User">User</option>
                        <option value="Admin">Admin</option>
                    </InputSelect>
                </div>
                <div class="col-md-3">
                    <button type="submit" class="btn btn-primary w-100">Send invite</button>
                </div>
            </div>
        </EditForm>
        @if (message is not null)
        {
            <div class="alert @(isError ? "alert-danger" : "alert-success") mt-3 mb-0">
                @message
                @if (lastAcceptUrl is not null)
                {
                    <div class="small mt-1">
                        If email isn't configured, share this link directly:<br />
                        <code>@lastAcceptUrl</code>
                    </div>
                }
            </div>
        }
    </div>
</div>

<h5>Pending invitations</h5>
@if (pending is null)
{
    <p>Loading…</p>
}
else if (pending.Count == 0)
{
    <p class="text-secondary">No pending invitations.</p>
}
else
{
    <table class="table">
        <thead><tr><th>Email</th><th>Role</th><th>Expires</th><th></th></tr></thead>
        <tbody>
            @foreach (var i in pending)
            {
                <tr>
                    <td>@i.Email</td>
                    <td>@i.Role</td>
                    <td class="small @(i.ExpiresAt < DateTimeOffset.UtcNow ? "text-danger" : "")">
                        @i.ExpiresAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm")
                        @if (i.ExpiresAt < DateTimeOffset.UtcNow)
                        {
                            <span>(expired)</span>
                        }
                    </td>
                    <td class="text-end">
                        <button class="btn btn-outline-danger btn-sm" @onclick="() => RevokeAsync(i.Id)">Revoke</button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private InviteForm form = new();
    private List<Invite>? pending;
    private string? message;
    private string? lastAcceptUrl;
    private bool isError;

    protected override async Task OnInitializedAsync() => await LoadAsync();

    private async Task LoadAsync()
    {
        await using var db = await DbFactory.CreateDbContextAsync();
        pending = await db.Invites
            .Where(i => i.AcceptedAt == null)
            .OrderByDescending(i => i.Id) // Id grows with creation; SQLite can't ORDER BY DateTimeOffset
            .ToListAsync();
    }

    private async Task CreateAsync()
    {
        message = null;
        lastAcceptUrl = null;
        var adminId = await AuthState.GetUserIdAsync();
        var result = await InviteSvc.CreateInviteAsync(form.Email, form.Role, adminId!);
        isError = !result.Succeeded;
        if (result.Succeeded)
        {
            message = $"Invitation sent to {form.Email}.";
            lastAcceptUrl = result.AcceptUrl;
            form = new InviteForm();
        }
        else
        {
            message = result.Error;
        }
        await LoadAsync();
    }

    private async Task RevokeAsync(int id)
    {
        await using var db = await DbFactory.CreateDbContextAsync();
        await db.Invites.Where(i => i.Id == id).ExecuteDeleteAsync();
        await LoadAsync();
    }

    private sealed class InviteForm
    {
        [Required, EmailAddress]
        public string Email { get; set; } = "";
        public string Role { get; set; } = "User";
    }
}
