import 'babel-core/register';
import 'babel-polyfill';
import express from 'express';
import request from 'request-promise';
import bodyParser from 'body-parser';
import _debug from 'debug';
import human2date from 'date.js';
import config from '../config.json';
import { formatDate } from './utils';
import * as db from './db';

const INCOMING_WEBHOOK_URL = config.slack.incomingWebhookURL;

const debug = _debug('pledge');

const postOnSlack = json => request({
  json: { username: 'pledge', icon_emoji: ':dog:', ...json },
  url: INCOMING_WEBHOOK_URL,
  method: 'POST'
});

const postOnSlackMultipleChannels =
  (json, channels) => Promise.all(channels.map(c => postOnSlack({ channel: c, ...json })));

async function newPledge({ text, requester }) {
  const [, performer, content, humanReadableDeadline] = /(@[a-zA-Z0-9]+) (.+) by (.+)/.exec(text.trim()) || [];

  if (!performer) {
    throw new Error('"Username" is missing. (@username [what] by [when])');
  } else if (!content) {
    throw new Error('"What" is missing. (@username [what] by [when])');
  } else if (!humanReadableDeadline) {
    throw new Error('"When" is missing. (@username [what] by [when])');
  }

  const deadline = human2date(humanReadableDeadline);

  if (deadline.getTime() < Date.now()) {
    throw new Error('"When" should be in the future');
  }

  await db.insertPledge({ requester, performer, content, deadline }).then(debug);

  await postOnSlack({
    text: `${requester} asked you to "${content}" by ${humanReadableDeadline} (${formatDate(deadline)})`,
    channel: performer
  });

  return `You asked ${performer} to "${content}" by ${humanReadableDeadline} (${formatDate(deadline)})`;
}

async function getPledgesList(requester) {
  const { requests, pledges } = await db.getList(requester);

  const baseURL = 'https://pledge.our.buildo.io';

  const myPledges = `*My pledges:*\n${pledges.map(p => `\n • ${p.content} _for ${p.requester}_ *by ${p.deadline}* <${baseURL}/deletePledge/${p.id}|delete> <${baseURL}/completePledge/${p.id}|complete>`)}`;
  const myRequests = `*My requests:*\n${requests.map(p => `\n • _${p.performer}_ pledged to ${p.content} *by ${p.deadline}* <${baseURL}/deletePledge/${p.id}|delete> <${baseURL}/completePledge/${p.id}|complete>`)}`;

  return `${myPledges}\n\n${myRequests}`;
}

// EXPRESS SERVER

const app = express();

app.use(bodyParser.urlencoded({ extended: false }));

app.post('/slackCommand', async ({ body: { text, user_name } }, res) => {
  debug({ text, user_name });
  const requester = `@${user_name}`;

  try {
    switch (text.trim()) {
      case 'list':
        return res.send(await getPledgesList(requester));
      default:
        return res.send(await newPledge({ text, requester }));
    }
  } catch (err) {
    debug(err);
    res.send(`Error: ${err.message}`);
  }
});

app.get('/deletePledge/:pledgeId', async ({ params: { pledgeId } }, res) => {
  try {
    const { requester, performer, content } = await db.getPledge(pledgeId);
    await db.deletePledge(pledgeId);
    // notify on slack
    const notificationMessage = `pledge "${content}" has been deleted`;
    await postOnSlack({
      text: notificationMessage,
      channel: performer
    });
    await postOnSlack({
      text: notificationMessage,
      channel: requester
    });
    res.send(`Successfully deleted pledge #${pledgeId}`);
  } catch (e) {
    res.send(`Error: ${e.message}`);
  }
});

app.get('/completePledge/:pledgeId', async ({ params: { pledgeId } }, res) => {
  try {
    const { requester, performer, content } = await db.getPledge(pledgeId);
    await db.completePledge(pledgeId);
    // notify on slack
    const notificationMessage = `pledge "${content}" has been completed !!!`;
    await postOnSlack({
      text: notificationMessage,
      channel: performer
    });
    await postOnSlack({
      text: notificationMessage,
      channel: requester
    });
    res.send(`Successfully completed pledge #${pledgeId}`);
  } catch (e) {
    res.send(`Error: ${e.message}`);
  }
});

async function findNewNotifications() {
  // notify for pledges that have expired
  const expiredPledges = await db.findAllPledgesExpiredToNotify();
  expiredPledges.map(async p => {
    await postOnSlackMultipleChannels({
      text: `pledge ${p.content} expired just now`
    }, [p.requester, p.performer]);
    await db.setExpiredNotificationAsSentOnPledge(p.id);
  });
}

setInterval(findNewNotifications, 60 * 1000);

app.listen(3000, db.init);

@@ -2295,16 +2295,439 @@
 s%7D%60;%0A%7D%0A%0A
+async function findNewNotifications() %7B%0A  // notify for pledges that have expired%0A  const expiredPledges = await db.findAllPledgesExpiredToNotify();%0A  expiredPledges.map(async p =%3E %7B%0A    await postOnSlackMultipleChannels(%7B%0A      text: %60pledge $%7Bp.content%7D expired just now%60%0A    %7D, %5Bp.requester, p.performer%5D);%0A    await db.setExpiredNotificationAsSentOnPledge(p.id);%0A  %7D);%0A%7D%0A%0AsetInterval(findNewNotifications, 60 * 1000);%0A%0A
 // EXPRE
@@ -4439,431 +4439,8 @@
 );%0A%0A
-async function findNewNotifications() %7B%0A  // notify for pledges that have expired%0A  const expiredPledges = await db.findAllPledgesExpiredToNotify();%0A  expiredPledges.map(async p =%3E %7B%0A    await postOnSlackMultipleChannels(%7B%0A      text: %60pledge $%7Bp.content%7D expired just now%60%0A    %7D, %5Bp.requester, p.performer%5D);%0A    await db.setExpiredNotificationAsSentOnPledge(p.id);%0A  %7D);%0A%7D%0A%0AsetInterval(findNewNotifications, 60 * 1000);%0A%0A
 app.

reorganize order of functions