import type RedisInstance from "ioredis";

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

async function fetchEndpoint(
  redis: RedisInstance,
  query: string,
  gql: boolean = false
) {
  if (await redis.get("7TV.RATE_LIMIT")) {
    await new Promise((resolve) => setTimeout(resolve, 1000));
  } else {
    await redis.set("7TV.RATE_LIMIT", "1", "EX", 1);
  }
  if (gql) {
    const response = await fetchGQL(query);
    const json = response.data;
    return json;
  } else {
    const response = await fetch(query);
    const json = await response.json();
    return json;
  }
}

async function fetchGQL(query: string) {
  const response = await fetch("https://7tv.io/v3/gql", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: query,
    }),
  });
  const json = await response.json();
  return json;
}

async function getGlobalEmotes(redis: RedisInstance) {
  const gqlQuery = `query {
        namedEmoteSet(name: GLOBAL) {
            emote_count
            emotes {
                flags
                id
                name
                data {
                    animated
                    flags
                    id
                    name
                    tags
                    host {
                        files {
                            format
                            height
                            width
                            name
                            size
                        }
                        url
                    }
                }
            }
        }
    }`;
  return await applyCache(redis, "7TV.GLOBAL_EMOTES", gqlQuery, true, 3600);
}

async function getChannelEmotes(redis: RedisInstance, channelID: string) {
  const gqlQuery = `query {
        user(id: "${channelID}") {
            emote_sets {
                emote_count
                emotes(origins: true) {
                    flags
                    id
                    name
                    data {
                        animated
                        flags
                        id
                        name
                        tags
                        host {
                            files {
                                format
                                height
                                width
                                name
                                size
                            }
                            url
                        }
                    }
                }
            }
        }
    }`;
  return await applyCache(
    redis,
    "7TV.CHANNEL_EMOTES_" + channelID,
    gqlQuery,
    true,
    1200
  );
}

export { getGlobalEmotes, getChannelEmotes };
