const chalk = require('chalk');
const composer = require('./updaters/composer');
const fs = require('fs');
const getConfig = require('./config');
const inquirer = require('inquirer');
const readlineSync = require('readline-sync');
const rp = require('request-promise');
const shelljs = require('shelljs');
const wp = require('./updaters/wp');

module.exports = () => {
  require('./greeter')(`What projects do you want to update?`);

  const batchConfig = getConfig();
  const preferredProjects = batchConfig.projects || [];
  const choices = fs.readdirSync('.')
    .filter(folder => fs.lstatSync(folder).isDirectory())
    .map(folder => ({ name: folder, checked: preferredProjects.includes(folder) }));

  inquirer.prompt([{
    choices,
    type: 'checkbox',
    message: 'Select projects',
    name: 'projects',
    pageSize: 30,
  }]).then(({ projects }) => {
    if (!projects.length) {
      console.error(chalk.red('ERROR: You have selected no projects to update.'));
      return;
    }

    fs.writeFileSync('.apparatusrc', JSON.stringify({ projects }));

    let githubUser = shelljs.exec(`git config --global github.user`, { silent: true }).stdout.trim();
    let githubToken = shelljs.exec(`git config --global github.token`, { silent: true }).stdout.trim();

    if (!githubUser) {
      githubUser = readlineSync.question(chalk.yellow(`Please enter your GitHub username: `));
      shelljs.exec(`git config --global github.user ${githubUser}`, { silent: true });
    }

    if (!githubToken) {
      githubToken = readlineSync.question(chalk.yellow(`Please enter your GitHub access token: `), { hideEchoBack: true });
      shelljs.exec(`git config --global github.token ${githubToken}`, { silent: true });
    }

    const repositoryVersions = {};
    const pullRequests = [];

    projects.forEach(project => {
      console.log(chalk.magenta(`Running update sequence for ${chalk.bold(project)}..`));

      shelljs.cd(project);

      const branchName = `updates-${Date.now()}`;
      shelljs.exec(`git branch ${branchName} master`, { silent: true });
      shelljs.exec(`git checkout ${branchName}`, { silent: true });

      if (fs.existsSync('composer.json')) {
        console.log(chalk.blue(`Updating version constraints..`));

        const config = getConfig();
        const skipPackages = config.composerSkip || [];
        const composerConfig = JSON.parse(fs.readFileSync('composer.json', 'utf-8'));

        const updateRepositories = composerConfig.repositories
          .filter(repository => repository.type === 'package')
          .filter(repository => !skipPackages.includes(repository.package.name))
          .map(repository => {
            const name = repository.package.name;
            const version = repositoryVersions[name] || readlineSync.question(chalk.yellow(`What version of ${chalk.bold(name)} would you like to install? (now: ${chalk.bold(repository.package.version)}) `))

            return { name, version };
          })
          .filter(repository => repository.version);

        if (updateRepositories.length) {            
          updateRepositories.forEach(({ name, version }) => {
            repositoryVersions[name] = version;

            composerConfig.repositories.forEach(repository => {
              if (repository.type === 'package' && repository.package.name === name) {
                repository.package.version = version;

                if (repository.package.source) {
                  repository.package.source.reference = version;
                }
              }
            });
          });

          fs.writeFileSync('composer.json', JSON.stringify(composerConfig, null, 2));
        }

        const packageUpdates = composer.getOutdatedAfterUpdate()
          .split('\n')
          .map(composerPackage => composerPackage.split(/\s+/))
          .filter(([name]) => !skipPackages.includes(name));

        const joinDeps = deps => deps
            .map(([name, currentVersion, availableVersion]) => `${name} ${availableVersion}`)
            .join(' ');

        const devDependencies = packageUpdates.filter(([name]) => Object.keys(composerConfig['require-dev']).includes(name));
        const dependencies = packageUpdates.filter(composerPackage => !devDependencies.includes(composerPackage));

        shelljs.exec(`composer require ${joinDeps(dependencies)} --no-update`, { silent: true });
        shelljs.exec(`composer require ${joinDeps(devDependencies)} --no-update --dev`, { silent: true });
      } else if (!wp.used()) {
        console.log(chalk.red(`ERROR: No valid WordPress environment found for ${project}.`))
        shelljs.cd('..');

        return;
      }

      console.log(chalk.blue(`Running ${chalk.bold('UPDATE APPARATUS')}..`));
      shelljs.exec(`${__dirname}/../index.js --yes`, { silent: true });

      const diff = fs.readFileSync('updates.diff', 'utf-8');
      shelljs.rm('updates.diff');

      const title = '⬆️ Update dependencies';
      const body = 'Auto-update by UPDATE APPARATUS 🤖';

      if (fs.existsSync('composer.json')) {
        shelljs.exec(`git commit composer.json composer.lock -m "${title}\n\n${body}"`, { silent: true });
      } else {
        shelljs.exec(`git add -A && git commit -m "${title}\n\n${body}"`, { silent: true });
      }

      shelljs.exec(`git push origin ${branchName}`, { silent: true });

      const repoUrl = shelljs.exec(`git config remote.origin.url`, { silent: true }).stdout.trim();
      const repoName = repoUrl.substr(repoUrl.lastIndexOf(':') + 1).replace('.git', '');

      const diffHtml = '<details><summary>Diff</summary>\n\n```diff\n' + diff + '\n```\n</details>';

      pullRequests.push(rp({
        auth: {
          user: githubUser,
          pass: githubToken,
        },
        body: {
          base: 'master',
          body: '```\n' + body + '\n```\n\n' + diffHtml,
          head: branchName,
          title,
        },
        headers: {
          'User-Agent': 'UPDATE APPARATUS',
        },
        json: true,
        method: 'POST',
        uri: `https://api.github.com/repos/${repoName}/pulls`,
      }));

      shelljs.cd('..');
    });

    Promise.all(pullRequests)
      .then(responses => {
        console.log(chalk.green(`SUCCESS: Projects have been updated succesfully. Please review the pull request for each project:`));

        responses.forEach(response => {
          console.log(chalk.dim(response.html_url));
        });
      });
  });
}

@@ -513,21 +513,99 @@
 jects %7C%7C
+ %7B%7D;%0A  const directoryPreferredProjects = preferredProjects%5Bprocess.cwd()%5D %7C%7C
  %5B%5D;%0A
+%0A
   const 
@@ -737,17 +737,26 @@
 hecked: 
-p
+directoryP
 referred
@@ -1074,24 +1074,73 @@
 urn;%0A    %7D%0A%0A
+    preferredProjects%5Bprocess.cwd()%5D = projects;%0A
     fs.write
@@ -1189,16 +1189,35 @@
 projects
+: preferredProjects
  %7D));%0A%0A 

Split project preferences across directories