// ioredis types
import Redis from "ioredis";

async function applyCache(
  redis: Redis,
  key: string,
  query: string,
  cacheTime: number
) {
  if (await redis.get(key)) {
    return JSON.parse((await redis.get(key)) as string);
  } else {
    const response = await fetchEndpoint(redis, query);
    if (response != null) {
      await redis.set(key, JSON.stringify(response), "EX", cacheTime);
    }
    return response;
  }
}

async function authTwitch(redis: Redis) {
  let auth = await redis.get("TWITCH.AUTH");
  if (auth) {
    return auth;
  } else {
    const response = await fetch(
      `https://id.twitch.tv/oauth2/token?client_id=${process.env.TWITCH_CLIENT_ID}&client_secret=${process.env.TWITCH_SECRET}&grant_type=client_credentials`,
      {
        method: "POST",
      }
    );
    const json = await response.json();
    await redis.set("TWITCH.OAUTH", json.access_token, "EX", json.expires_in);

    return json.access_token;
  }
}

async function fetchEndpoint(redis: Redis, query: string) {
  if (await redis.get("TWITCH.RATE_LIMIT")) {
    await new Promise((resolve) => setTimeout(resolve, 1000));
  } else {
    await redis.set("TWITCH.RATE_LIMIT", "1", "EX", 1);
  }

  const auth = await authTwitch(redis);

  const requestHeaders = new Headers();
  requestHeaders.append("Client-ID", process.env.TWITCH_CLIENT_ID ?? "");
  requestHeaders.append("Authorization", `Bearer ${auth}`);

  const response = await fetch(query, {
    headers: requestHeaders,
  });
  const json = await response.json();
  return json;
}

async function getUserByName(redis: Redis, username: string) {
  return await applyCache(
    redis,
    "TWITCH.USER_" + username,
    `https://api.twitch.tv/helix/users?login=${username}`,
    600
  );
}

async function getUserByID(redis: Redis, userID: string) {
  return await applyCache(
    redis,
    "TWITCH.USER_" + userID,
    `https://api.twitch.tv/helix/users?id=${userID}`,
    600
  );
}

async function getGlobalEmotes(redis: Redis) {
  return await applyCache(
    redis,
    "TWITCH.GLOBAL_EMOTES",
    `https://api.twitch.tv/helix/chat/emotes/global`,
    3600
  );
}

async function getChannelEmotes(redis: Redis, channelID: string) {
  return await applyCache(
    redis,
    "TWITCH.CHANNEL_EMOTES_" + channelID,
    `https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelID}`,
    600
  );
}

export { getUserByName, getUserByID, getGlobalEmotes, getChannelEmotes };
