namespace DodoSSH.Client.Auth;

/// <summary>
/// Everything needed to talk to one identity provider.
/// </summary>
/// <remarks>
/// Populated from the DodoSSH server's <c>/.well-known/dodossh-configuration</c>, which is the whole
/// onboarding story: the user types one server URL and the client discovers the authority, the client
/// id and the scopes from it.
/// </remarks>
public sealed record OidcClientOptions
{
    /// <summary>The provider's issuer URL.</summary>
    public required Uri Authority { get; init; }

    /// <summary>The public client identifier registered for the desktop app.</summary>
    public required string ClientId { get; init; }

    /// <summary>
    /// Scopes requested at sign-in.
    /// </summary>
    /// <remarks>
    /// <c>offline_access</c> is what yields a refresh token, and without one the user re-authenticates
    /// through the browser every time the access token expires.
    /// </remarks>
    public IReadOnlyList<string> Scopes { get; init; } = ["openid", "profile", "email", "offline_access"];

    /// <summary>Path the loopback listener answers the redirect on.</summary>
    public string RedirectPath { get; init; } = "/callback";

    /// <summary>
    /// How the authorization response is received. Loopback unless a head substitutes one.
    /// </summary>
    /// <remarks>
    /// <para>
    /// A factory rather than an instance, because a callback owns a socket or a system registration and
    /// must not outlive one sign-in. It takes the redirect path so the default keeps behaving exactly as
    /// it did when it was constructed inline.
    /// </para>
    /// <para>
    /// The Android head replaces this: a loopback redirect on a shared device is the attack RFC 8252 §8.3
    /// names, since any other application can bind the port. See <see cref="IAuthorizationCallback"/>.
    /// </para>
    /// </remarks>
    public Func<string, IAuthorizationCallback> CallbackFactory { get; init; } =
        path => new LoopbackCallbackListener(path);

    /// <summary>Whether provider metadata must be served over HTTPS. Only false for local development.</summary>
    public bool RequireHttpsMetadata { get; init; } = true;

    /// <summary>How long to wait for the user to finish in the browser.</summary>
    /// <remarks>
    /// Generous, because the user may have to find a password manager, complete a second factor, or
    /// approve a push notification on another device.
    /// </remarks>
    public TimeSpan BrowserTimeout { get; init; } = TimeSpan.FromMinutes(5);

    /// <summary>Page shown in the browser once the callback is captured.</summary>
    public string CompletionHtml { get; init; } =
        """
        <!doctype html><html><head><meta charset="utf-8"><title>DodoSSH</title></head>
        <body style="font-family:system-ui;margin:4rem;text-align:center">
        <h1>Signed in</h1><p>You can close this tab and return to DodoSSH.</p>
        </body></html>
        """;
}
