import { firstExecuteRow } from '../execute-rows.js';
import { sql } from 'drizzle-orm';
import type { ModelOption } from '@/server/ai/providers/listModels.js';
import type { DrizzleClient } from '@/server/db/client';

export interface ModelCacheRow {
  models: ModelOption[];
  fetchedAt: string;
  error: string | null;
}

export async function getModelCache(
  db: DrizzleClient,
  providerId: string,
): Promise<ModelCacheRow | null> {
  type ModelCacheDbRow = {
    models: ModelOption[] | string;
    fetched_at: string | Date;
    error: string | null;
  };
  const result = await db.execute<ModelCacheDbRow>(sql`
    SELECT models, fetched_at, error
    FROM llm_model_cache
    WHERE provider_id = ${providerId}::uuid
  `);
  const row = firstExecuteRow<ModelCacheDbRow>(result);
  if (!row) return null;
  const models =
    typeof row.models === 'string' ? (JSON.parse(row.models) as ModelOption[]) : row.models;
  return {
    models,
    fetchedAt: new Date(row.fetched_at).toISOString(),
    error: row.error,
  };
}

export async function upsertModelCache(
  db: DrizzleClient,
  providerId: string,
  models: ModelOption[],
): Promise<void> {
  const modelsJson = JSON.stringify(models);
  await db.execute(sql`
    INSERT INTO llm_model_cache (provider_id, models, fetched_at, error)
    VALUES (${providerId}::uuid, ${modelsJson}::jsonb, now(), NULL)
    ON CONFLICT (provider_id) DO UPDATE
    SET models = EXCLUDED.models,
        fetched_at = now(),
        error = NULL
  `);
}

export async function setModelCacheError(
  db: DrizzleClient,
  providerId: string,
  error: string,
): Promise<void> {
  await db.execute(sql`
    INSERT INTO llm_model_cache (provider_id, models, fetched_at, error)
    VALUES (${providerId}::uuid, '[]'::jsonb, now(), ${error})
    ON CONFLICT (provider_id) DO UPDATE
    SET error = EXCLUDED.error,
        fetched_at = now()
  `);
}
