import { PrismaClient } from '@prisma/client';

import { FeatureKind } from '../../../core/features';
import { getLatestQuota } from '../../../core/quota/schema';
import { Quota, QuotaType } from '../../../core/quota/types';
import { upsertFeature } from './user-features';

export async function upgradeQuotaVersion(
  db: PrismaClient,
  quota: Quota,
  reason: string
) {
  // add new quota
  await upsertFeature(db, quota);
  // migrate all users that using old quota to new quota
  await db.$transaction(
    async tx => {
      const latestQuotaVersion = await tx.features.findFirstOrThrow({
        where: { feature: quota.feature },
        orderBy: { version: 'desc' },
        select: { id: true },
      });

      // find all users that have old free plan
      const userIds = await tx.user.findMany({
        where: {
          features: {
            some: {
              feature: {
                type: FeatureKind.Quota,
                feature: quota.feature,
                version: { lt: quota.version },
              },
              activated: true,
            },
          },
        },
        select: { id: true },
      });

      // deactivate all old quota for the user
      await tx.userFeatures.updateMany({
        where: {
          id: undefined,
          userId: {
            in: userIds.map(({ id }) => id),
          },
          feature: {
            type: FeatureKind.Quota,
          },
          activated: true,
        },
        data: {
          activated: false,
        },
      });

      await tx.userFeatures.createMany({
        data: userIds.map(({ id: userId }) => ({
          userId,
          featureId: latestQuotaVersion.id,
          reason,
          activated: true,
        })),
      });
    },
    {
      maxWait: 10000,
      timeout: 20000,
    }
  );
}

export async function upsertLatestQuotaVersion(
  db: PrismaClient,
  type: QuotaType
) {
  const latestQuota = getLatestQuota(type);
  await upsertFeature(db, latestQuota);
}

export async function upgradeLatestQuotaVersion(
  db: PrismaClient,
  type: QuotaType,
  reason: string
) {
  const latestQuota = getLatestQuota(type);
  await upgradeQuotaVersion(db, latestQuota, reason);
}
