import { and, eq, isNull } from 'drizzle-orm';
import type { DrizzleClient } from '../client.js';
import { pushSubscriptions, vendors } from '../schema.js';

export interface SavePushSubscriptionInput {
  userId: string;
  endpoint: string;
  p256dh: string;
  auth: string;
  userAgent?: string;
}

export interface RemovePushSubscriptionInput {
  userId: string;
  endpoint: string;
}

export async function savePushSubscription(
  db: DrizzleClient,
  input: SavePushSubscriptionInput,
): Promise<void> {
  await db
    .insert(pushSubscriptions)
    .values({
      userId: input.userId,
      endpoint: input.endpoint,
      p256dh: input.p256dh,
      auth: input.auth,
      userAgent: input.userAgent ?? '',
      revokedAt: null,
    })
    .onConflictDoUpdate({
      target: pushSubscriptions.endpoint,
      set: {
        userId: input.userId,
        p256dh: input.p256dh,
        auth: input.auth,
        userAgent: input.userAgent ?? '',
        revokedAt: null,
      },
    });
}

export async function revokePushSubscription(
  db: DrizzleClient,
  input: RemovePushSubscriptionInput,
): Promise<void> {
  await db
    .update(pushSubscriptions)
    .set({ revokedAt: new Date() })
    .where(
      and(
        eq(pushSubscriptions.userId, input.userId),
        eq(pushSubscriptions.endpoint, input.endpoint),
      ),
    );
}

export async function deletePushSubscriptionByEndpoint(
  db: DrizzleClient,
  endpoint: string,
): Promise<void> {
  await db.delete(pushSubscriptions).where(eq(pushSubscriptions.endpoint, endpoint));
}

export async function listPushSubscriptionsForUser(db: DrizzleClient, userId: string) {
  return db
    .select()
    .from(pushSubscriptions)
    .where(and(eq(pushSubscriptions.userId, userId), isNull(pushSubscriptions.revokedAt)));
}

export async function listPushSubscriptionsForVendor(db: DrizzleClient, vendorId: string) {
  const result = await db
    .select({ subscription: pushSubscriptions })
    .from(pushSubscriptions)
    .innerJoin(vendors, eq(vendors.ownerUserId, pushSubscriptions.userId))
    .where(and(eq(vendors.id, vendorId), isNull(pushSubscriptions.revokedAt)));

  return result.map((r) => r.subscription);
}
