import { and, eq, lte, lt, inArray, sql } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client.js';
import { translationMemory } from '@/server/db/schema.js';

export async function touchTranslationMemory(
  db: DrizzleClient,
  input: { sourceHash: string; srcLocale: string; tgtLocale: string },
): Promise<void> {
  await db
    .update(translationMemory)
    .set({ lastUsedAt: sql`now()`, usageCount: sql`${translationMemory.usageCount} + 1` })
    .where(
      and(
        eq(translationMemory.sourceHash, input.sourceHash),
        eq(translationMemory.sourceLocale, input.srcLocale),
        eq(translationMemory.targetLocale, input.tgtLocale),
      ),
    );
}

export async function touchTranslationMemoryBatch(
  db: DrizzleClient,
  input: { sourceHash: string[]; srcLocale: string; tgtLocale: string },
): Promise<void> {
  await db
    .update(translationMemory)
    .set({ lastUsedAt: sql`now()`, usageCount: sql`${translationMemory.usageCount} + 1` })
    .where(
      and(
        inArray(translationMemory.sourceHash, input.sourceHash),
        eq(translationMemory.sourceLocale, input.srcLocale),
        eq(translationMemory.targetLocale, input.tgtLocale),
      ),
    );
}

export async function upsertTranslationMemory(
  db: DrizzleClient,
  rows: Array<{
    sourceHash: string;
    sourceText: string;
    translatedText: string;
    modelId: string;
    sourceLocale: string;
    targetLocale: string;
  }>,
): Promise<void> {
  if (rows.length === 0) return;
  await db
    .insert(translationMemory)
    .values(rows)
    .onConflictDoUpdate({
      target: [
        translationMemory.sourceHash,
        translationMemory.sourceLocale,
        translationMemory.targetLocale,
      ],
      set: { lastUsedAt: sql`now()`, usageCount: sql`${translationMemory.usageCount} + 1` },
    });
}

export async function evictTranslationMemory(
  db: DrizzleClient,
  opts: { olderThanDays?: number; minUsageCount?: number },
): Promise<{ deleted: number }> {
  if (opts.olderThanDays == null && opts.minUsageCount == null)
    throw new Error('tmEvict: at least one of olderThanDays or minUsageCount must be set');
  const predicates = [];
  if (opts.olderThanDays != null)
    predicates.push(
      lt(translationMemory.lastUsedAt, sql`now() - (${opts.olderThanDays} || ' days')::interval`),
    );
  if (opts.minUsageCount != null)
    predicates.push(lte(translationMemory.usageCount, opts.minUsageCount));
  const deleted = await db
    .delete(translationMemory)
    .where(and(...predicates))
    .returning({ sourceHash: translationMemory.sourceHash });
  return { deleted: deleted.length };
}
