import { eq, and, type Db, preferences } from '@mosaicstack/db';

export type Preference = typeof preferences.$inferSelect;
export type NewPreference = typeof preferences.$inferInsert;

export function createPreferencesRepo(db: Db) {
  return {
    async findByUser(userId: string): Promise<Preference[]> {
      return db.select().from(preferences).where(eq(preferences.userId, userId));
    },

    async findByUserAndKey(userId: string, key: string): Promise<Preference | undefined> {
      const rows = await db
        .select()
        .from(preferences)
        .where(and(eq(preferences.userId, userId), eq(preferences.key, key)));
      return rows[0];
    },

    async findByUserAndCategory(
      userId: string,
      category: Preference['category'],
    ): Promise<Preference[]> {
      return db
        .select()
        .from(preferences)
        .where(and(eq(preferences.userId, userId), eq(preferences.category, category)));
    },

    async upsert(data: NewPreference): Promise<Preference> {
      const existing = await db
        .select()
        .from(preferences)
        .where(and(eq(preferences.userId, data.userId), eq(preferences.key, data.key)));

      if (existing[0]) {
        const rows = await db
          .update(preferences)
          .set({ value: data.value, category: data.category, updatedAt: new Date() })
          .where(eq(preferences.id, existing[0].id))
          .returning();
        return rows[0]!;
      }

      const rows = await db.insert(preferences).values(data).returning();
      return rows[0]!;
    },

    async remove(userId: string, key: string): Promise<boolean> {
      const rows = await db
        .delete(preferences)
        .where(and(eq(preferences.userId, userId), eq(preferences.key, key)))
        .returning();
      return rows.length > 0;
    },
  };
}

export type PreferencesRepo = ReturnType<typeof createPreferencesRepo>;
