import { renderStatsCard } from "../src/cards/stats.js";
import { blacklist } from "../src/common/blacklist.js";
import { whitelist } from "../src/common/whitelist.js";
import {
  clampValue,
  CONSTANTS,
  parseArray,
  parseBoolean,
  renderError,
} from "../src/common/utils.js";
import { fetchStats } from "../src/fetchers/stats.js";
import { isLocaleAvailable } from "../src/translations.js";
import { storeRequest } from "../src/common/database.js";

export default async (req, res) => {
  const {
    username,
    repo,
    owner,
    hide,
    hide_title,
    hide_border,
    card_width,
    hide_rank,
    show_icons,
    include_all_commits,
    line_height,
    title_color,
    ring_color,
    icon_color,
    text_color,
    text_bold,
    bg_color,
    theme,
    cache_seconds,
    exclude_repo,
    custom_title,
    locale,
    disable_animations,
    border_radius,
    number_format,
    role,
    border_color,
    rank_icon,
    show,
  } = req.query;
  res.setHeader("Content-Type", "image/svg+xml");

  if (whitelist && !whitelist.includes(username)) {
    return res.send(
      renderError(
        "This username is not whitelisted",
        "Please deploy your own instance",
        {
          title_color,
          text_color,
          bg_color,
          border_color,
          theme,
          show_repo_link: false,
        },
      ),
    );
  }

  if (whitelist === undefined && blacklist.includes(username)) {
    return res.send(
      renderError(
        "This username is blacklisted",
        "Please deploy your own instance",
        {
          title_color,
          text_color,
          bg_color,
          border_color,
          theme,
          show_repo_link: false,
        },
      ),
    );
  }

  if (locale && !isLocaleAvailable(locale)) {
    return res.send(
      renderError("Something went wrong", "Language not found", {
        title_color,
        text_color,
        bg_color,
        border_color,
        theme,
      }),
    );
  }

  const safePattern = /^[-\w\/.,]+$/;
  if (
    (username && !safePattern.test(username)) ||
    (repo && !safePattern.test(repo)) ||
    (owner && !safePattern.test(owner))
  ) {
    return res.send(
      renderError(
        "Something went wrong",
        "Username, repository or owner contains unsafe characters",
        {
          title_color,
          text_color,
          bg_color,
          border_color,
          theme,
        },
      ),
    );
  }

  try {
    await storeRequest(req);
    const showStats = parseArray(show);
    const repoOwner = parseArray(owner);
    let repository = parseArray(repo);
    repository = repository.map((repo) =>
      repo.includes("/") ? repo : `${username}/${repo}`,
    );

    const stats = await fetchStats(
      username,
      parseBoolean(include_all_commits),
      parseArray(exclude_repo),
      showStats.includes("prs_merged") ||
        showStats.includes("prs_merged_percentage"),
      showStats.includes("discussions_started"),
      showStats.includes("discussions_answered"),
      repository,
      repoOwner,
      showStats.includes("prs_authored"),
      showStats.includes("prs_commented"),
      showStats.includes("prs_reviewed"),
      showStats.includes("issues_authored"),
      showStats.includes("issues_commented"),
      parseArray(role),
    );

    let cacheSeconds = clampValue(
      parseInt(cache_seconds || CONSTANTS.CARD_CACHE_SECONDS, 10),
      CONSTANTS.FOUR_HOURS,
      CONSTANTS.TWO_DAY,
    );
    cacheSeconds = process.env.CACHE_SECONDS
      ? parseInt(process.env.CACHE_SECONDS, 10) || cacheSeconds
      : cacheSeconds;

    res.setHeader(
      "Cache-Control",
      `max-age=${cacheSeconds}, s-maxage=${cacheSeconds}, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
    );

    return res.send(
      renderStatsCard(
        stats,
        {
          hide: parseArray(hide),
          show_icons: parseBoolean(show_icons),
          hide_title: parseBoolean(hide_title),
          hide_border: parseBoolean(hide_border),
          card_width: parseInt(card_width, 10),
          hide_rank: parseBoolean(hide_rank),
          include_all_commits: parseBoolean(include_all_commits),
          line_height,
          title_color,
          ring_color,
          icon_color,
          text_color,
          text_bold: parseBoolean(text_bold),
          bg_color,
          theme,
          custom_title,
          border_radius,
          border_color,
          number_format,
          locale: locale ? locale.toLowerCase() : null,
          disable_animations: parseBoolean(disable_animations),
          rank_icon,
          show: showStats,
        },
        username,
        repository,
        repoOwner,
      ),
    );
  } catch (err) {
    res.setHeader(
      "Cache-Control",
      `max-age=${CONSTANTS.ERROR_CACHE_SECONDS / 2}, s-maxage=${
        CONSTANTS.ERROR_CACHE_SECONDS
      }, stale-while-revalidate=${CONSTANTS.ONE_DAY}`,
    ); // Use lower cache period for errors.
    return res.send(
      renderError(err.message, err.secondaryMessage, {
        title_color,
        text_color,
        bg_color,
        border_color,
        theme,
      }),
    );
  }
};
