import {db, DBTransaction} from '@db/index';
import {assets, messagesToAssets} from '@db/schema';
import {eq, isNull, sql} from 'drizzle-orm';

import {InsertAsset} from '../interfaces';

export const saveAssets = async (
  assetsToInsert: InsertAsset[],
  messageId: string,
  tx?: DBTransaction,
) => {
  if (!assetsToInsert.length) {
    return;
  }

  const builder = tx ?? db.instance;
  const normalizedAssets = assetsToInsert.map(asset => ({
    id: asset.id,
    mimetype: asset.mimetype,
    filename: asset.filename,
    format: asset.format,
    url: asset.url ?? null,
    size: asset.size ?? null,
    image_url: asset.image_url ?? null,
    image_bytes: asset.image_bytes ?? null,
    image_height: asset.image_height ?? null,
    image_width: asset.image_width ?? null,
    external_reference: asset.external_reference ?? null,
    audio_duration_ms: asset.audio_duration_ms ?? 0,
    is_valid: asset.is_valid ?? null,
    video_duration_ms: asset.video_duration_ms ?? 0,
    thumbnail_url: asset.thumbnail_url ?? null,
    is_available: asset.is_available ?? null,
  }));

  await builder
    .insert(assets)
    .values(normalizedAssets)
    .onConflictDoUpdate({
      target: assets.id,
      set: {
        thumbnail_url: sql`excluded.thumbnail_url`,
        is_valid: sql`excluded.is_valid`,
        is_available: sql`excluded.is_available`,
      },
      // Update the thumbnail_url only if the asset is a video and the thumbnail_url is not already set
      setWhere: sql`
        (${assets.format} = 'video' 
        AND ${isNull(assets.thumbnail_url)} 
        AND excluded.thumbnail_url IS NOT NULL
      ) OR (
        ${assets.format} = 'audio' 
        AND (${isNull(assets.is_valid)} OR ${assets.is_valid} = false)
        AND excluded.is_valid IS true
      ) OR (
        ${assets.format} = 'gif'
        AND ${assets.is_available} = true
        AND excluded.is_available IS false
      ) OR ${assets.url} IS NULL OR ${assets.image_url} IS NULL`,
    });

  const messageAssets = normalizedAssets.map(asset => ({
    message_id: messageId,
    asset_id: asset.id!,
  }));

  await builder
    .insert(messagesToAssets)
    .values(messageAssets)
    .onConflictDoNothing();
};

export const updateAsset = (assetId: number, updates: Partial<InsertAsset>) => {
  return db.instance
    .update(assets)
    .set(updates)
    .where(eq(assets.id, assetId))
    .execute();
};

export const getAllAssets = async () => {
  return await db.instance.query.assets.findMany();
};
