import { createWriteStream, promises } from "fs";
import got from "got";
import { tmpdir } from "os";
import { join } from "path";
import { Stream } from "stream";
import tar from "tar";
import { promisify } from "util";
import { makeDir } from "./make-dir";

export type RepoInfo = {
  username: string;
  name: string;
  branch: string;
  filePath: string;
};

const pipeline = promisify(Stream.pipeline);

async function downloadTar(url: string) {
  const tempFile = join(tmpdir(), `next.js-cna-example.temp-${Date.now()}`);
  await pipeline(got.stream(url), createWriteStream(tempFile));
  return tempFile;
}

export async function downloadAndExtractRepo(
  root: string,
  { username, name, branch, filePath }: RepoInfo,
) {
  await makeDir(root);

  const tempFile = await downloadTar(
    `https://codeload.github.com/${username}/${name}/tar.gz/${branch}`,
  );

  await tar.x({
    file: tempFile,
    cwd: root,
    strip: filePath ? filePath.split("/").length + 1 : 1,
    filter: (p) =>
      p.startsWith(
        `${name}-${branch.replace(/\//g, "-")}${
          filePath ? `/${filePath}/` : "/"
        }`,
      ),
  });

  await promises.unlink(tempFile);
}

export async function getRepoRootFolders(
  owner: string,
  repo: string,
): Promise<string[]> {
  const url = `https://api.github.com/repos/${owner}/${repo}/contents`;

  const response = await got(url, {
    responseType: "json",
  });

  const data = response.body as any[];
  const folders = data.filter((item) => item.type === "dir");
  return folders.map((item) => item.name);
}

export async function getRepoRawContent(repoFilePath: string) {
  const url = `https://raw.githubusercontent.com/${repoFilePath}`;
  const response = await got(url, {
    responseType: "text",
  });
  return response.body;
}