using Spectre.Console;
using ZB.MOM.WW.Secrets.Abstractions;

namespace ZB.MOM.WW.Secrets.Cli.Interactive.Flows;

/// <summary>
/// Creates or rotates a secret: prompts for a validated name, confirms before overwriting an existing
/// live row, reads the value through a masked prompt, and seals it under a fresh per-secret DEK via the
/// session cipher. The value is never echoed and the confirmation line carries the name only. Requires a
/// KEK-capable session (the shell upgrades a degraded session before dispatch).
/// </summary>
public sealed class SetSecretFlow : IInteractiveFlow
{
    /// <inheritdoc />
    public string Title => "Set / rotate a secret";

    /// <inheritdoc />
    public bool RequiresKek => true;

    /// <inheritdoc />
    public async Task RunAsync(IAnsiConsole console, SecretsSession session, CancellationToken ct)
    {
        ArgumentNullException.ThrowIfNull(console);
        ArgumentNullException.ThrowIfNull(session);

        ISecretCipher cipher = session.Cipher
            ?? throw new InvalidOperationException("flow requires an unlocked KEK session");

        var name = new SecretName(console.Prompt(
            new TextPrompt<string>("Secret [green]name[/]:").Validate(FlowPrompts.ValidateSecretName)));

        StoredSecret? existing = await session.Store.GetAsync(name, ct).ConfigureAwait(false);
        if (existing is { IsDeleted: false } &&
            !console.Prompt(new ConfirmationPrompt($"'{name.Value}' exists — overwrite in place?") { DefaultValue = false }))
        {
            console.MarkupLine("[yellow]Left unchanged.[/]");
            return;
        }

        string value = console.Prompt(new TextPrompt<string>("Secret [green]value[/]:").Secret());
        SecretContentType contentType = console.Prompt(
            new SelectionPrompt<SecretContentType>().Title("Content type").AddChoices(Enum.GetValues<SecretContentType>()));
        string description = console.Prompt(
            new TextPrompt<string>("Description [grey](optional)[/]:").AllowEmpty());

        string actor = FlowPrompts.Actor;
        StoredSecret row = cipher.Encrypt(name, value, contentType) with
        {
            Description = string.IsNullOrWhiteSpace(description) ? null : description,
            CreatedBy = actor,
            UpdatedBy = actor,
        };
        await session.Store.UpsertAsync(row, ct).ConfigureAwait(false);

        console.MarkupLineInterpolated($"[green]Sealed '{name.Value}'.[/]");
    }
}
