namespace DodoSSH.Domain;

/// <summary>
/// The shape every encrypted vault item shares.
/// </summary>
/// <remarks>
/// <para>
/// Each item type keeps its own table — the plan's data model, and the reason is per-type constraints
/// rather than tidiness: the relay CHECK on <c>host</c> has no meaning for an SSH key, and a single table
/// would have to make every such column nullable and enforce nothing. What the types genuinely share is
/// this: opaque ciphertext, the key generation it was sealed under, a client-visible version for optimistic
/// concurrency, a change-log pointer, and a tombstone.
/// </para>
/// <para>
/// An interface rather than a base class, deliberately. EF Core maps an inheritance hierarchy when it can
/// see one, and a mapped base would quietly become a table-per-hierarchy discriminator across item types —
/// which is the arrangement this interface exists to avoid. An interface carries no mapping semantics, so
/// each concrete type stays an independent entity with its own table while the write path can still be
/// written once.
/// </para>
/// <para>
/// Note what is <em>not</em> here. <c>xmin</c> is never exposed, because it is not stable across
/// <c>VACUUM FREEZE</c> and must not become a client cursor. Plaintext columns are not here either: they
/// are exactly the part that differs per type, and they are the part with privacy consequences, so they are
/// handled explicitly per type rather than through a shared abstraction that could grow one by accident.
/// </para>
/// </remarks>
public interface IVaultItem
{
    /// <summary>Primary key. UUIDv7, generated by the client so items can be created offline.</summary>
    Guid Id { get; set; }

    /// <summary>Owning vault.</summary>
    Guid VaultId { get; set; }

    /// <summary>The encrypted item: a DSH1 envelope. Opaque to the server.</summary>
    byte[] Payload { get; set; }

    /// <summary>The item's data key, wrapped under the vault key. Opaque.</summary>
    byte[]? DataKeyWrap { get; set; }

    /// <summary>Reserved for per-item content keys wrapped to individual users; see docs/crypto.md §3.</summary>
    Guid? ContentKeyId { get; set; }

    /// <summary>Vault key generation this payload was encrypted under.</summary>
    int KeyGeneration { get; set; }

    /// <summary>AAD rule version, enabling a lazy re-encrypt-on-write migration later.</summary>
    short PayloadAadVersion { get; set; }

    /// <summary>Client-visible, monotonic item version, used for <c>expectedVersion</c> checks.</summary>
    int Version { get; set; }

    /// <summary>Latest change-log sequence touching this row, so a delta pull can join directly.</summary>
    long ChangeSequence { get; set; }

    /// <summary>Creation timestamp.</summary>
    DateTimeOffset CreatedAtUtc { get; set; }

    /// <summary>Last modification timestamp.</summary>
    DateTimeOffset UpdatedAtUtc { get; set; }

    /// <summary>Soft-delete marker. Deletes are tombstones so an offline client can learn of them.</summary>
    DateTimeOffset? DeletedAtUtc { get; set; }

    /// <summary>Who created it.</summary>
    Guid CreatedByUserId { get; set; }

    /// <summary>Who last modified it.</summary>
    Guid UpdatedByUserId { get; set; }
}
