import { and, eq, gt } from "drizzle-orm";
import createClient from "openapi-fetch";
import db from "~/drizzle";
import { cache } from "~/drizzle/schema";
import { paths } from "~/types/discord";
import getAccessToken from "./accessToken";

type Guilds =
  paths["/users/@me/guilds"]["get"]["responses"]["200"]["content"]["application/json"];

type Channels =
  paths["/guilds/{guild_id}/channels"]["get"]["responses"]["200"]["content"]["application/json"];

export const { GET: discordApi } = createClient<paths>({
  baseUrl: "https://discord.com/api/v10",
});

export async function userGuilds(userId: string) {
  const path = "/users/@me/guilds";
  const key = `${path}:${userId}`;
  const consoleKey = `${path.green}:${userId.yellow}`;

  const tokens = await getAccessToken(userId);
  if (!tokens) {
    console.log("No discord access token!");
    return null;
  }

  const currentDate = new Date();
  const fifteenMinutesAgo = new Date(currentDate.getTime() - 15 * 60 * 1000);

  let guilds: Guilds | undefined = JSON.parse(
    (
      await db.query.cache
        .findFirst({
          where: and(
            eq(cache.key, key),
            gt(cache.createdAt, fifteenMinutesAgo),
          ),
        })
        .execute()
    )?.value ?? "null",
  );

  if (!guilds) {
    const { data, error } = await discordApi(path, {
      headers: { Authorization: `Bearer ${tokens.accessToken}` },
    });

    if (error) console.log("Discord api error:", { error });

    guilds = data;

    const set = {
      key,
      value: JSON.stringify(data),
      createdAt: currentDate,
    };
    await db.insert(cache).values(set).onConflictDoUpdate({
      set,
      target: cache.key,
    });
    console.log("To cache written.", consoleKey);
  } else {
    console.log("Cache value used!", consoleKey);
  }

  return guilds;
}

export async function guildChannels(guildId: bigint) {
  const path = "/guilds/{guild_id}/channels";
  const key = `${path}:${String(guildId)}`;
  const consoleKey = `${path.green}:${String(guildId).yellow}`;

  const currentDate = new Date();
  const fifteenMinutesAgo = new Date(currentDate.getTime() - 15 * 60 * 1000);

  let channels: Channels | undefined = JSON.parse(
    (
      await db.query.cache
        .findFirst({
          where: and(
            eq(cache.key, key),
            gt(cache.createdAt, fifteenMinutesAgo),
          ),
        })
        .execute()
    )?.value ?? "null",
  );

  if (!channels) {
    const { data, error } = await discordApi(path, {
      params: {
        path: {
          guild_id: String(guildId),
        },
      },
      headers: {
        Authorization: `Bot ${import.meta.env.VITE_DISCORD_BOT_TOKEN}`,
      },
    });

    if (error) console.log("Discord api error:", { error });

    channels = data;

    const set = {
      key,
      value: JSON.stringify(data),
      createdAt: currentDate,
    };
    await db.insert(cache).values(set).onConflictDoUpdate({
      set,
      target: cache.key,
    });

    console.log("To cache written.", consoleKey);
  } else {
    console.log("Cache value used!", consoleKey);
  }

  return channels;
}
