/* eslint-disable flowtype/require-valid-file-annotation */
// Jest loads this file and can't transpile it.
const fs = require('fs');
const request = require('request-promise-native');

const USER_AGENT = 'Eyebot/1.0.0';
const MARKDOWN_PREAMBLE = `
# Visual Diffs Detected

It looks like your PR has introduced visual changes in the UI. I don't know if this was intentional or not.

Please take a look at the diffs below. If these were intended changes, please ignore this comment. \
Diffs are based on latest master, so a PR rebase may fix the test failures.

If some of them are unexpected, you might have some visual regressions to fix before you merge.

Add **[skip eyebot]** or **[eyebot skip]** to your commit message to disable this bot.
`;

const NEW_STORY_MESSAGE = `
It looks like you have added a new story. Please **disregard** the storyshots test failure as no valid diffs have been generated.

Add **[skip eyebot]** or **[eyebot skip]** to your commit message to disable this bot.
`;

const envOrDie = varname => {
  const val = process.env[varname];
  if (undefined === val) {
    throw new Error(`Missing required environment variable: ${varname}`);
  }

  return val;
};

// Used with storyshots and jest-image-snapshot. Creates/updates
// a comment on the PR with links to any failed diff images.
class GithubPrImageDiffReporter {
  constructor(globalConfig, options) {
    this._globalConfig = globalConfig;
    this._options = options;

    this.repoName = envOrDie('CIRCLE_PROJECT_REPONAME');
    this.ghApiUser = envOrDie('DEVTOOLS_GITHUB_USERNAME');
    this.ghApiToken = envOrDie('DEVTOOLS_GITHUB_API_TOKEN');
    this.buildNum = envOrDie('CIRCLE_BUILD_NUM');
    this.circleNodeIndex = envOrDie('CIRCLE_NODE_INDEX');
    this.gitCommit = envOrDie('CIRCLE_SHA1');
  }

  async onRunComplete(contexts, results) {
    // eslint-disable-next-line no-console
    console.log('Test results: ', results);

    // Do not post diff in __diff_output__ does not exist
    if (!fs.existsSync('./src/__image_snapshots__/__diff_output__/')) {
      // eslint-disable-next-line no-console
      console.log('No diff output detected');

      // If any of the Test Results have failures.
      const hasCreatedNewStory = results.testResults.some(
        result =>
          result.failureMessage &&
          result.failureMessage.includes(
            'The update flag must be explicitly passed to write a new snapshot',
          ),
      );

      if (hasCreatedNewStory) {
        // eslint-disable-next-line no-console
        console.log('New stories have been created');

        await request({
          method: 'POST',
          uri: `https://api.github.com/repos/wealthsimple/${this.repoName}/commits/${this.gitCommit}/comments`,
          body: {
            body: `${NEW_STORY_MESSAGE}\n\n> generator: ${USER_AGENT}`,
          },
          headers: {
            'User-Agent': USER_AGENT,
            'Content-type': 'application/json',
          },
          json: true,
        }).auth(this.ghApiUser, this.ghApiToken, true);
      }
      return;
    }

    const response = await request({
      url: `https://api.github.com/repos/wealthsimple/${this.repoName}`,
      headers: { 'User-Agent': USER_AGENT },
      json: true,
    }).auth(this.ghApiUser, this.ghApiToken, true);

    const ghRepoId = response.id;

    const messageMarkdown = fs
      .readdirSync('./src/__image_snapshots__/__diff_output__/')
      .map(fileName => this.toMessageRecord(fileName, ghRepoId))
      .reduce(
        (message, record) =>
          `${message}\n* [${record.linkText}](${record.imageUrl})`,
        MARKDOWN_PREAMBLE,
      );

    // eslint-disable-next-line no-console
    console.log('Diffs detected: Posting comment');
    await request({
      method: 'POST',
      uri: `https://api.github.com/repos/wealthsimple/${this.repoName}/commits/${this.gitCommit}/comments`,
      body: {
        body: `${messageMarkdown}\n\n> generator: ${USER_AGENT}`,
      },
      headers: {
        'User-Agent': USER_AGENT,
        'Content-type': 'application/json',
      },
      json: true,
    }).auth(this.ghApiUser, this.ghApiToken, true);
  }

  toMessageRecord(diffFileName, ghRepoId) {
    return {
      imageUrl: this.toCircleArtifactUrl(diffFileName, ghRepoId),
      linkText: diffFileName.replace(
        'storyshots-shots-js-image-storyshots-',
        '',
      ),
    };
  }

  toCircleArtifactUrl(diffFileName, repoId) {
    return `https://${this.buildNum}-${repoId}-gh.circle-artifacts.com/${this.circleNodeIndex}/src/__image_snapshots__/__diff_output__/${diffFileName}`;
  }
}

module.exports = GithubPrImageDiffReporter;
