/// Mirrors `inviteResp` from internal/api/admin_invites.go. The list
/// endpoint wraps these in `{"invites": [...]}`; the create endpoint
/// returns a single bare invite. Envelope parsing is done in
/// `AdminInvitesApi`, not here.
///
/// `invitedBy` is the UUID of the inviting admin (not their username);
/// the server doesn't currently denormalize it. Likewise `redeemedBy`.
/// TTL is hardcoded server-side at 24h, so admins can't customise the
/// expiry — only the optional `note`.
class Invite {
  const Invite({
    required this.token,
    required this.invitedBy,
    this.note,
    required this.createdAt,
    required this.expiresAt,
    this.redeemedAt,
    this.redeemedBy,
  });

  final String token;
  final String invitedBy;
  final String? note;
  final String createdAt;
  final String expiresAt;
  final String? redeemedAt;
  final String? redeemedBy;

  bool get isRedeemed => redeemedAt != null;

  factory Invite.fromJson(Map<String, dynamic> j) => Invite(
        token: j['token'] as String? ?? '',
        invitedBy: j['invited_by'] as String? ?? '',
        note: j['note'] as String?,
        createdAt: j['created_at'] as String? ?? '',
        expiresAt: j['expires_at'] as String? ?? '',
        redeemedAt: j['redeemed_at'] as String?,
        redeemedBy: j['redeemed_by'] as String?,
      );
}
