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

namespace DodoSSH.Client.Sync;

/// <summary>
/// The groups in this vault, decrypted, with unpushed local changes laid over them.
/// </summary>
/// <remarks>
/// <para>
/// The fifth facade over the same generic repository, and like the fourth it needed no new sync logic at all.
/// </para>
/// <para>
/// <b>Deleting a group still does not touch the hosts in it, here.</b> There is deliberately no
/// <c>DeleteAsync</c> overload that unfiles its members: one call would become N host writes, N outbox rows
/// and N chances to merge against an edit nobody made, and the group's own tombstone can still lose a merge —
/// by which time the membership it was clearing would be gone. A host left holding a dangling id falls under
/// the ungrouped heading, so this layer is safe whatever happens above it. See
/// <see cref="HostSecret.GroupId"/>.
/// </para>
/// <para>
/// What changed above it is that the deletion is no longer silent about the choice: the interface asks
/// whether the hosts should go too, and writes them one by one through <c>HostRepository</c> either way —
/// as N deletions, or as N hosts with the reference cleared. That is the same N writes, made where somebody
/// asked for them and where the count can be shown before the fact rather than issued by a repository call
/// that reads like one delete.
/// </para>
/// </remarks>
public sealed class HostGroupRepository(
    ItemStore items,
    OutboxStore outbox,
    VaultKeyring keyring,
    IActivityLogSink? activity = null)
{
    private readonly VaultItemRepository<HostGroupSecret> groups =
        new(HostGroupKind.Instance, items, outbox, keyring, activity);

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

    /// <inheritdoc cref="VaultItemRepository{TSecret}.CreateAsync" />
    public Task<Guid> CreateAsync(
        Guid vaultId,
        HostGroupSecret group,
        CancellationToken cancellationToken) =>
        groups.CreateAsync(vaultId, group, cancellationToken);

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

    /// <inheritdoc cref="VaultItemRepository{TSecret}.MoveAsync" />
    /// <remarks>
    /// <inheritdoc cref="VaultItemRepository{TSecret}.MoveAsync" path="/remarks" />
    /// <para>
    /// The new id matters more for a group than for anything else that can be moved, because a group is the
    /// one item other items point at. Everything naming the old id — the hosts filed under it, the groups
    /// nested inside it — has to be rewritten with the id this returns, or it is left pointing at a
    /// tombstone. That rewriting is the caller's, for the reason the <c>secret</c> parameter is: this layer
    /// cannot know which references cross with the group and which stay behind.
    /// </para>
    /// </remarks>
    public Task<Guid> MoveAsync(
        Guid fromVaultId,
        Guid toVaultId,
        Guid entityId,
        HostGroupSecret group,
        CancellationToken cancellationToken) =>
        groups.MoveAsync(fromVaultId, toVaultId, entityId, group, cancellationToken);

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