let { Octokit } = await npm("octokit");
const GH_PERSONAL_ACCESS_TOKEN = await env("GH_PERSONAL_ACCESS_TOKEN");
const octokit = new Octokit({ auth: GH_PERSONAL_ACCESS_TOKEN });
const ORGS_PER_PAGE = 20;
const REPOS_PER_PAGE = 100;
const GetAccounts = `query GetAccounts($first: Int) { 
  viewer { 
    organizations(first: $first) {
      edges {
        node {
          login
          name
          url
        }
      }
    }
    login
    name
    url
  }
}`;
const ReposPage = `fragment ReposPage on RepositoryConnection {
  edges {
    node {
      name
      description
      url
    }
  }
  pageInfo {
    endCursor
    hasNextPage
  }
}`;
const GetOrgRepos = `query GetOrgRepos($first: Int, $after: String, $login: String!) {
  viewer { 
    organization(login: $login) {
      repositories(
        first: $first
        after: $after
        orderBy: { field: UPDATED_AT, direction: DESC }
      ) {
        ...ReposPage
      }
    }
  }
}
${ReposPage}
`;
const GetUserRepos = `query GetUserRepos($first: Int, $after: String) {
  viewer { 
    repositories(
      first: $first
      after: $after
      orderBy: {field: UPDATED_AT, direction: DESC}
      affiliations: OWNER
    ) {
      ...ReposPage
    }
  }
}
${ReposPage}
`;
let dots = 0;
const accountsPlaceholderIntervalId = setInterval(() => {
  setPlaceholder(`Loading GitHub accounts`.padEnd(++dots, "."));
}, 100);
const { viewer } = await octokit.graphql(GetAccounts, { first: ORGS_PER_PAGE });
if (!viewer) {
  exit(1);
}
const { login, name, url, organizations } = viewer;
const accounts = [
  { name, value: login, description: url, type: "user" },
  ...organizations.edges.map(({ node: { login, name, url } }) => ({
    name,
    value: login,
    description: url,
    type: "org"
  }))
].sort((a, b) => (a.name > b.name ? 1 : -1));
clearInterval(accountsPlaceholderIntervalId);
dots = 0;
const accountChoice = await arg("Which account?", accounts);
const { type: accountType } = accounts.find(
  account => accountChoice === account.value
);
let repositoriesAndLoadMore = [];
async function fetchRepositories(variables) {
  const reposPlaceholderIntervalId = setInterval(() => {
    setPlaceholder(`Loading repositories`.padEnd(++dots, "."));
  }, 100);
  let edges, endCursor, hasNextPage;
  const oldLoadMore = repositoriesAndLoadMore.find(({ value }) =>
    value.startsWith("load-more-after-")
  );
  if (oldLoadMore) {
    repositoriesAndLoadMore.pop();
  }
  if (accountType === "org") {
    ({
      viewer: {
        organization: {
          repositories: {
            edges,
            pageInfo: { endCursor, hasNextPage }
          }
        }
      }
    } = await octokit.graphql(GetOrgRepos, {
      login: accountChoice,
      ...variables
    }));
  } else {
    ({
      viewer: {
        repositories: {
          edges,
          pageInfo: { endCursor, hasNextPage }
        }
      }
    } = await octokit.graphql(GetUserRepos, variables));
  }
  repositoriesAndLoadMore = [
    ...repositoriesAndLoadMore,
    ...edges.map(({ node: { description, name, url } }) => ({
      name,
      description,
      value: url
    }))
  ];
  if (hasNextPage) {
    repositoriesAndLoadMore.push({
      name: "Load more...",
      value: `load-more-after-${endCursor}`
    });
  }
  clearInterval(reposPlaceholderIntervalId);
  dots = 0;
  if (!repositoriesAndLoadMore.length) {
    exit(1);
  }
  let repoChoice = await arg("Which project?", repositoriesAndLoadMore);
  if (repoChoice.startsWith("load-more-after-")) {
    await fetchRepositories({
      first: REPOS_PER_PAGE,
      after: repoChoice.split("-").pop()
    });
  } else {
    exec(`open ${repoChoice}`);
  }
}
await fetchRepositories({ first: REPOS_PER_PAGE });