import { Prisma, PrismaClient } from "@prisma/client";
import { DiscordAuthProvider } from "./auth/discord";
import { getLogger } from "./logger";

const logger = getLogger("prisma.ts");

async function refreshDiscordTokens(prisma: PrismaClient) {
  // refresh 6 hours before expiry
  const refreshWindow = 6 * 60 * 60 * 1000;

  const discordAuths = await prisma.discordAuth.findMany({
    where: {
      expiresAt: {
        lte: new Date(Date.now() + refreshWindow)
      },
      invalid: false
    }
  });

  for (const discordAuth of discordAuths) {
    const data = await DiscordAuthProvider.refreshToken(
      discordAuth.refreshToken
    );

    if (data === null) {
      logger.warn(
        {
          user: discordAuth.userId,
          id: discordAuth.id
        },
        "failed to refresh discord token"
      );

      await prisma.discordAuth.update({
        where: {
          id: discordAuth.id
        },
        data: {
          invalid: true
        }
      });
    } else {
      await prisma.discordAuth.update({
        where: {
          id: discordAuth.id
        },
        data: {
          accessToken: data.access_token,
          refreshToken: data.refresh_token,
          expiresAt: new Date(Date.now() + data.expires_in * 1000)
        }
      });
    }
  }
}

async function expireTickets(prisma: PrismaClient) {
  const expired = await prisma.authTicket.findMany({
    where: {
      expiresAt: {
        lte: new Date()
      }
    }
  });

  for (const ticket of expired) {
    await prisma.authTicket.delete({
      where: {
        id: ticket.id
      }
    });
  }
}

let prisma: PrismaClient;
if (global.prisma == undefined) {
  global.prisma = new PrismaClient();
  prisma = global.prisma;

  setInterval(async () => {
    await refreshDiscordTokens(prisma);
    await expireTickets(prisma);
  }, 60 * 1000);
} else {
  prisma = global.prisma;
}

export default prisma;
