using DodoSSH.Client.Domain;
using DodoSSH.Client.Storage;

namespace DodoSSH.Client.Sync;

/// <summary>
/// The SSH keys in a vault, decrypted, with unpushed local changes laid over them.
/// </summary>
/// <remarks>
/// <para>
/// Identical in shape to <see cref="HostRepository"/> and identical in implementation, because both are
/// facades over the same generic repository. The only thing that differs is the item kind, and with it
/// the cipher, the merge, and the fact that a key sends the server no plaintext columns at all.
/// </para>
/// <para>
/// <b>A key listed here has its private key in memory.</b> Listing is not a cheap metadata read: it
/// decrypts every key in the vault, so the caller holds the material for as long as it holds the listing.
/// That is the same bargain <see cref="HostRepository"/> makes for passwords in notes and the reason
/// <c>SshKeySecret</c> documents what managed strings do and do not give you — but it is worth stating
/// where the decryption actually happens, which is here.
/// </para>
/// </remarks>
public sealed class SshKeyRepository(
    ItemStore items,
    OutboxStore outbox,
    VaultKeyring keyring,
    IActivityLogSink? activity = null)
{
    private readonly VaultItemRepository<SshKeySecret> keys =
        new(SshKeyKind.Instance, items, outbox, keyring, activity);

    /// <inheritdoc cref="VaultItemRepository{TSecret}.ListAsync" />
    public Task<ItemListing<SshKeySecret>> ListAsync(
        Guid vaultId,
        CancellationToken cancellationToken) =>
        keys.ListAsync(vaultId, cancellationToken);

    /// <inheritdoc cref="VaultItemRepository{TSecret}.CreateAsync" />
    public Task<Guid> CreateAsync(Guid vaultId, SshKeySecret key, CancellationToken cancellationToken) =>
        keys.CreateAsync(vaultId, key, cancellationToken);

    /// <inheritdoc cref="VaultItemRepository{TSecret}.UpdateAsync" />
    public Task UpdateAsync(
        Guid vaultId,
        Guid entityId,
        SshKeySecret key,
        CancellationToken cancellationToken) =>
        keys.UpdateAsync(vaultId, entityId, key, cancellationToken);

    /// <inheritdoc cref="VaultItemRepository{TSecret}.MoveAsync" />
    /// <remarks>
    /// <para>
    /// The same two writes a host's move is, and the reason a key needs one at all is what a vault is for:
    /// a key created in a personal vault before a team existed is the key the team's hosts authenticate
    /// with, and until this existed the only way to get it across was to paste the private half into a
    /// second item and delete the first — which is a private key on a clipboard, and two items nobody can
    /// tell apart afterwards.
    /// </para>
    /// <para>
    /// <b>It lands with a new id</b>, as everything moved does, so every host and group default naming the
    /// old one is left pointing at a tombstone. Re-aiming them is the caller's, because only the caller
    /// knows which of them it is allowed to rewrite — see <c>VaultViewModel.ReAimAtAsync</c>.
    /// </para>
    /// </remarks>
    public Task<Guid> MoveAsync(
        Guid fromVaultId,
        Guid toVaultId,
        Guid entityId,
        SshKeySecret key,
        CancellationToken cancellationToken) =>
        keys.MoveAsync(fromVaultId, toVaultId, entityId, key, cancellationToken);

    /// <inheritdoc cref="VaultItemRepository{TSecret}.DeleteAsync" />
    public Task DeleteAsync(Guid vaultId, Guid entityId, CancellationToken cancellationToken) =>
        keys.DeleteAsync(vaultId, entityId, cancellationToken);
}
