// Copyright 2025 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import { z } from 'zod';
import { convertUndefinedToNull } from '../../util/dropNull.std.ts';
import { messageAttachmentTypeSchema } from '../../types/AttachmentDownload.std.ts';
import { APPLICATION_OCTET_STREAM } from '../../types/MIME.std.ts';
import type { MessageAttachmentDBType } from '../Interface.std.ts';

const permissiveStringOrNull = z
  .string()
  .optional()
  .transform(convertUndefinedToNull)
  // oxlint-disable-next-line promise/prefer-await-to-then
  .catch(null);
const permissiveNumberOrNull = z
  .number()
  .optional()
  .transform(convertUndefinedToNull)
  // oxlint-disable-next-line promise/prefer-await-to-then
  .catch(null);
const permissiveAttachmentVersion = z
  .union([z.literal(1), z.literal(2)])
  .optional()
  .transform(convertUndefinedToNull)
  // oxlint-disable-next-line promise/prefer-await-to-then
  .catch(null);
const permissiveOptionalBool = z
  .union([z.literal(0), z.literal(1)])
  .optional()
  .transform(convertUndefinedToNull)
  // oxlint-disable-next-line promise/prefer-await-to-then
  .catch(null);

// A schema which converts invalid values to null, to handle bad data when
// attachments were stored in JSON
export const permissiveMessageAttachmentSchema = z.object({
  // Fields required to be NOT NULL
  messageId: z.string(),
  messageType: z.string(),
  editHistoryIndex: z.number(),
  attachmentType: messageAttachmentTypeSchema,
  orderInMessage: z.number(),
  conversationId: z.string(),
  // oxlint-disable-next-line promise/prefer-await-to-then
  sentAt: z.number().catch(0),
  // oxlint-disable-next-line promise/prefer-await-to-then
  receivedAt: z.number().catch(0),
  // oxlint-disable-next-line promise/prefer-await-to-then
  size: z.number().catch(0),
  // oxlint-disable-next-line promise/prefer-await-to-then
  contentType: z.string().catch(APPLICATION_OCTET_STREAM),

  // Fields allowing NULL
  receivedAtMs: permissiveNumberOrNull,
  duration: permissiveNumberOrNull,
  path: permissiveStringOrNull,
  clientUuid: permissiveStringOrNull,
  localKey: permissiveStringOrNull,
  plaintextHash: permissiveStringOrNull,
  caption: permissiveStringOrNull,
  blurHash: permissiveStringOrNull,
  height: permissiveNumberOrNull,
  width: permissiveNumberOrNull,
  digest: permissiveStringOrNull,
  key: permissiveStringOrNull,
  fileName: permissiveStringOrNull,
  downloadPath: permissiveStringOrNull,
  transitCdnKey: permissiveStringOrNull,
  transitCdnNumber: permissiveNumberOrNull,
  transitCdnUploadTimestamp: permissiveNumberOrNull,
  backupCdnNumber: permissiveNumberOrNull,
  incrementalMac: permissiveStringOrNull,
  incrementalMacChunkSize: permissiveNumberOrNull,
  thumbnailPath: permissiveStringOrNull,
  thumbnailSize: permissiveNumberOrNull,
  thumbnailContentType: permissiveStringOrNull,
  thumbnailLocalKey: permissiveStringOrNull,
  thumbnailVersion: permissiveAttachmentVersion,
  screenshotPath: permissiveStringOrNull,
  screenshotSize: permissiveNumberOrNull,
  screenshotContentType: permissiveStringOrNull,
  screenshotLocalKey: permissiveStringOrNull,
  screenshotVersion: permissiveAttachmentVersion,
  backupThumbnailPath: permissiveStringOrNull,
  backupThumbnailSize: permissiveNumberOrNull,
  backupThumbnailContentType: permissiveStringOrNull,
  backupThumbnailLocalKey: permissiveStringOrNull,
  backupThumbnailVersion: permissiveAttachmentVersion,
  storyTextAttachmentJson: permissiveStringOrNull,
  localBackupPath: permissiveStringOrNull,
  flags: permissiveNumberOrNull,
  error: permissiveOptionalBool,
  wasTooBig: permissiveOptionalBool,
  backfillError: permissiveOptionalBool,
  isCorrupted: permissiveOptionalBool,
  isViewOnce: permissiveOptionalBool,
  copiedFromQuotedAttachment: permissiveOptionalBool,
  version: permissiveAttachmentVersion,
  pending: permissiveOptionalBool,
}) satisfies z.ZodType<MessageAttachmentDBType>;
