// Fix Close.io opportunity owners

'use strict';
if (process.argv.length !== 8) {
  log("Usage: node <script> <Close.io general API key> <Close.io mail API key1> <Close.io mail API key2> <Close.io mail API key3> <Close.io EU mail API key>");
  process.exit();
}

const scriptStartTime = new Date();
const closeIoApiKey = process.argv[2];
const closeIoMailApiKeys = [process.argv[3], process.argv[4], process.argv[5], process.argv[6], process.argv[7]];
const async = require('async');
const request = require('request');

// ** Main program

getUsers((err, ownerId, userApiKeyMap) => {
  if (err) {
    console.error(err);
    return;
  }
  getOpps(ownerId, (err, opps) => {
    if (err) {
      console.error(err);
      return;
    }
    log(`${opps.length} opps owned by ${userApiKeyMap[ownerId].data.first_name}`);
    const tasks = [];
    for (const opp of opps) {
      tasks.push(createUpdateOppFn(ownerId, userApiKeyMap, opp));
    }
    async.parallel(tasks, (err, results) => {
      if (err) console.error(err);
      log("Script runtime: " + (new Date() - scriptStartTime));
    });
  });
});

function getUsers(done) {
  let ownerId = null;
  const userApiKeyMap = {};
  let createGetUserFn = (apiKey) => {
    return (done) => {
      const url = `https://${apiKey}:X@app.close.io/api/v1/me/`;
      request.get(url, (error, response, body) => {
        if (error) return done();
        const results = JSON.parse(body);
        userApiKeyMap[results.id] = {key: apiKey, data: results};
        if (apiKey === closeIoApiKey) {
          ownerId = results.id;
        }
        return done();
      });
    };
  }
  const tasks = [createGetUserFn(closeIoApiKey)];
  for (const apiKey of closeIoMailApiKeys) {
    tasks.push(createGetUserFn(apiKey));
  }
  async.parallel(tasks, (err, results) => {
    if (err) return done(err);
    return done(null, ownerId, userApiKeyMap);
  });
}

function getOpps(ownerId, done) {
  const url = `https://${closeIoApiKey}:X@app.close.io/api/v1/opportunity/?user_id=${ownerId}`;
  request.get(url, (err, response, body) => {
    if (err) return done(err);
    const results = JSON.parse(body);
    return done(null, results.data);
  });
}

function createUpdateOppFn(ownerId, userApiKeyMap, opp) {
  return (done) => {
    findOwner(ownerId, userApiKeyMap, opp, (err, userId) => {
      if (err) return done(err);
      // console.log(`DEBUG: ${opp.lead_id} owner ${userApiKeyMap[userId].data.first_name}`);
      return updateOpp(opp, userId, userApiKeyMap, done);
    });
  };
}

function findOwner(ownerId, userApiKeyMap, opp, done) {
  const url = `https://${closeIoApiKey}:X@app.close.io/api/v1/activity/?lead_id=${opp.lead_id}`;
  request.get(url, (err, response, body) => {
    if (err) return done(err);
    const results = JSON.parse(body);
    if (results.has_more) {
      console.log(`ERROR: ${lead.id} has more activities than ${results.data.length} returned!`);
    }
    for (const activity of results.data) {
      if (activity._type === 'Email' && userApiKeyMap[activity.user_id] && activity.user_id !== ownerId) {
        return done(null, activity.user_id);
      }
    }
    return done(`ERROR: No owner found for ${opp.lead_id}`);
  });
}

function updateOpp(opp, userId, userApiKeyMap, done) {
  const putData = {
    user_id: userId,
    user_name: `${userApiKeyMap[userId].data.first_name} ${userApiKeyMap[userId].data.last_name}`
  };
  console.log(`DEBUG: updating ${opp.lead_id} ${opp.id} to ${putData.user_name}`);
  const options = {
    uri: `https://${closeIoApiKey}:X@app.close.io/api/v1/opportunity/${opp.id}/`,
    body: JSON.stringify(putData)
  };
  request.put(options, (err, response, body) => {
    if (err) return done(err);
    const result = JSON.parse(body);
    if (result.errors || result['field-errors']) {
      console.log(`PUT error for ${opp.lead_id} ${opp.id}`);
      return done(result.errors || result['field-errors']);
    }
    return done();
  });
}

// ** Utilities

function log(str) {
  console.log(new Date().toISOString() + " " + str);
}