#!/usr/bin/env node

/**
 * External dependencies
 */
"use strict";

var _chalk = _interopRequireDefault(require("chalk"));

var _graphqlTag = _interopRequireDefault(require("graphql-tag"));

var _singleLineLog = require("single-line-log");

var _api = _interopRequireDefault(require("../lib/api"));

var _app2 = _interopRequireDefault(require("../lib/api/app"));

var _command = _interopRequireDefault(require("../lib/cli/command"));

var _format = require("../lib/cli/format");

var _tracker = require("../lib/tracker");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * Internal dependencies
 */
const appQuery = `id,name,environments{
	id,appId,type,name,defaultDomain,branch,datacenter,syncProgress{
		status,sync,steps{name,status}
	},syncPreview { canSync, errors { message }, backup { createdAt }, replacements { from, to } }
}`;
(0, _command.default)({
  appContext: true,
  appQuery: appQuery,
  childEnvContext: true,
  module: 'sync',
  requireConfirm: 'Are you sure you want to sync from production?'
}).argv(process.argv, async (arg, opts) => {
  const api = await (0, _api.default)();
  let syncing = false;
  await (0, _tracker.trackEvent)('sync_command_execute');

  try {
    await api.mutate({
      // $FlowFixMe: gql template is not supported by flow
      mutation: (0, _graphqlTag.default)`
						mutation SyncEnvironmentMutation($input: AppEnvironmentSyncInput){
							syncEnvironment(input: $input){
								environment{
									id
								}
							}
						}
					`,
      variables: {
        input: {
          id: opts.app.id,
          environmentId: opts.env.id
        }
      }
    });
  } catch (e) {
    if (e.graphQLErrors) {
      let bail = false;

      for (const err of e.graphQLErrors) {
        if (err.message !== 'Site is already syncing') {
          bail = true;
          console.log(_chalk.default.red('Error:'), err.message);
        }
      } // TODO: Log e


      if (bail) {
        return;
      }
    }

    syncing = true;
    await (0, _tracker.trackEvent)('sync_command_execute_error', {
      error: `Already syncing: ${e.message}`
    });
  }

  const sprite = {
    i: 0,
    sprite: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],

    next() {
      this.i++;

      if (this.i >= this.sprite.length) {
        this.i = 0;
      }

      return {
        value: this.sprite[this.i],
        done: false
      };
    }

  };
  const application = await (0, _app2.default)(opts.app.id, appQuery);
  let environment = application.environments.find(env => env.id === opts.env.id);

  if (syncing) {
    if (environment.syncProgress.status === 'running') {
      console.log(_chalk.default.yellow('Note:'), 'A data sync is already running');
    } else {
      console.log(_chalk.default.yellow('Note:'), 'Someone recently ran a data sync on this site');
      console.log(_chalk.default.yellow('Note:'), 'Please wait a few minutes before trying again');
    }
  }

  console.log();
  console.log(`  syncing: ${_chalk.default.yellow(opts.app.name)}`);
  console.log(`     from: ${(0, _format.formatEnvironment)('production')}`);
  console.log(`       to: ${(0, _format.formatEnvironment)(opts.env.type)}`);
  let i = 0;
  const progress = setInterval(async () => {
    if (i++ % 10 === 0) {
      // Query the API 1/10 of the time (every 1s)
      // The rest of the iterations are just for moving the spinner
      api.query({
        // $FlowFixMe: gql template is not supported by flow
        query: (0, _graphqlTag.default)`query App( $id: Int, $sync: Int ) {
							app( id: $id ){
								id,name,environments{
									id,name,defaultDomain,branch,datacenter,syncProgress( sync: $sync ){
										status,sync,steps{name,status}
									}
								}
							}
						}`,
        fetchPolicy: 'network-only',
        variables: {
          id: opts.app.id,
          sync: environment.syncProgress.sync
        }
      }).then(res => res.data.app).then(_app => {
        environment = _app.environments.find(env => env.id === opts.env.id);
      });
    }

    const marks = {
      pending: '○',
      running: _chalk.default.blueBright(sprite.next().value),
      success: _chalk.default.green('✓'),
      failed: _chalk.default.red('✕'),
      unknown: _chalk.default.yellow('✕')
    };
    const out = [];
    const steps = environment.syncProgress.steps || [];
    out.push('');
    steps.forEach(step => {
      if (step.status === 'pending') {
        out.push(_chalk.default.dim(` ${marks[step.status]} ${step.name}`));
      } else {
        out.push(` ${marks[step.status]} ${step.name}`);
      }
    });
    out.push('');

    switch (environment.syncProgress.status) {
      case 'running':
        out.push(`${marks.running} Press ^C to hide progress. Data sync will continue in the background.`);
        break;

      case 'failed':
        clearInterval(progress);
        await (0, _tracker.trackEvent)('sync_command_error', {
          error: 'API returned `failed` status'
        });
        out.push(`${marks.failed} Data Sync is finished for ${opts.app.name}`);
        out.push('');
        break;

      case 'success':
      default:
        clearInterval(progress);
        await (0, _tracker.trackEvent)('sync_command_success');
        out.push(`${marks.success} Data Sync is finished for ${opts.app.name}`);
        out.push('');
        break;
    }

    (0, _singleLineLog.stdout)(out.join('\n'));
  }, 100);
});