const process = require('process');
const path = require('path');
const fs = require('fs');
const YAML = require('yamljs');
const axios = require('axios');

const {promises} = fs;
const docsFile = path.join(__dirname, '../data/docs.yml')
const teamFile = path.join(__dirname, '../data/team.yml')

const sleep = (ms = 2 * 1000) => {
  console.log('waiting...');
  return new Promise(resolve => setTimeout(() => resolve(), ms));
}

class GenerateTeamYaml {
  constructor(docsFile, teamFile) {
    this.docsFile = docsFile;
    this.teamFile = teamFile;
    this.nativeObject = [];
    this.logins = {};
    this.mergedData = [];
  }

  async init() {
    try {
      console.log('start...');
      this.nativeObject = await this.loadYaml(docsFile);
      await this.getAllRepoData()
      await this.writeFile()
    } catch (err) {
      console.log(err);
      process.exit(1)
    }
  }

  async getAllRepoData() {
    const promiseList = [];
    for (const k of this.nativeObject) {
      for (const item of k.list) {
        const {user, repo, extraContributors} = item;
        const list = [];
        if (user && repo) {
          promiseList.push(this.getRepoContributors({user, repo, extraContributors, list, item}));
        }
        await sleep()
      }
    }
    await Promise.all(promiseList)
  }

  async writeFile() {
    const data = {
      totalCount: Object.keys(this.logins).length,
      projects: this.nativeObject
    }
    const yamlString = YAML.stringify(data);
    await promises.writeFile(this.teamFile, yamlString, 'utf8');
    console.log('team.yml success!');
  }

  async loadYaml() {
    const data = await new Promise((resolve) => {
      YAML.load(this.docsFile, (result) => {
        resolve(result)
      });
    })
    return data
  }

  handleData(data) {
    return data
        .filter((item) => item.type !== 'Bot')
        .map((item) => {
          const {type, email} = item;
          if (type === 'Anonymous') {
            item.login = email.replace(/(.+)@.+/, '$1**');
          }
          this.logins[item.login] = item.login;
          return item;
        });
  }

  async getRepoContributors({user, repo, extraContributors = [], page = 1, per_page = 100, list = [], item}) {
    let {data = []} = await axios.get(`https://api.github.com/repos/${user}/${repo}/contributors?page=${page}&per_page=${per_page}&anon=true&t=${new Date().getTime()}`)
    data = this.handleData(data);
    list.push(...data);
    if (data.length === per_page) {
      page++;
      await sleep()
      console.log(`/${user}/${repo}/contributors?page=${page}`)
      await this.getRepoContributors({user, repo, extraContributors, page, per_page, list, item})
    } else {
      if (extraContributors && extraContributors.length) {
        extraContributors.forEach(item => this.logins[item.login] = item.login);
      }
      const repoContributors = [...list, ...extraContributors];
      item.contributors = repoContributors;
      item.contributorCount = [...new Set(repoContributors.map(item => item.id || item.login))].length;
    }
  }
}

new GenerateTeamYaml(docsFile, teamFile).init()
