const request = require('request');
const AWS = require('aws-sdk');
const verifier = require('google-id-token-verifier');

const {
  USER_BUCKET_NAME = 'stackedit-users',
  PAYPAL_URI = 'https://www.paypal.com/cgi-bin/webscr',
  PAYPAL_RECEIVER_EMAIL = 'stackedit.project@gmail.com',
  GOOGLE_CLIENT_ID,
} = process.env;
const s3Client = new AWS.S3();

const cb = (resolve, reject) => (err, res) => {
  if (err) {
    reject(err);
  } else {
    resolve(res);
  }
};

exports.getUser = id => new Promise((resolve, reject) => {
  s3Client.getObject({
    Bucket: USER_BUCKET_NAME,
    Key: id,
  }, cb(resolve, reject));
})
  .then(
    res => JSON.parse(`${res.Body}`),
    (err) => {
      if (err.code !== 'NoSuchKey') {
        throw err;
      }
    },
  );

exports.putUser = (id, user) => new Promise((resolve, reject) => {
  s3Client.putObject({
    Bucket: USER_BUCKET_NAME,
    Key: id,
    Body: JSON.stringify(user),
  }, cb(resolve, reject));
});

exports.removeUser = id => new Promise((resolve, reject) => {
  s3Client.deleteObject({
    Bucket: USER_BUCKET_NAME,
    Key: id,
  }, cb(resolve, reject));
});

exports.getUserFromToken = idToken => new Promise((resolve, reject) => verifier
  .verify(idToken, GOOGLE_CLIENT_ID, cb(resolve, reject)))
  .then(tokenInfo => exports.getUser(tokenInfo.sub));

exports.userInfo = (req, res) => exports.getUserFromToken(req.query.idToken)
  .then(
    user => res.send(Object.assign({
      sponsorUntil: 0,
    }, user)),
    err => res
      .status(400)
      .send(err ? err.message || err.toString() : 'invalid_token'),
  );

exports.paypalIpn = (req, res, next) => Promise.resolve()
  .then(() => {
    const userId = req.body.custom;
    const paypalEmail = req.body.payer_email;
    const gross = parseFloat(req.body.mc_gross);
    let sponsorUntil;
    if (gross === 5) {
      sponsorUntil = Date.now() + (3 * 31 * 24 * 60 * 60 * 1000); // 3 months
    } else if (gross === 15) {
      sponsorUntil = Date.now() + (366 * 24 * 60 * 60 * 1000); // 1 year
    } else if (gross === 25) {
      sponsorUntil = Date.now() + (2 * 366 * 24 * 60 * 60 * 1000); // 2 years
    } else if (gross === 50) {
      sponsorUntil = Date.now() + (5 * 366 * 24 * 60 * 60 * 1000); // 5 years
    }
    if (
      req.body.receiver_email !== PAYPAL_RECEIVER_EMAIL ||
      req.body.payment_status !== 'Completed' ||
      req.body.mc_currency !== 'USD' ||
      (req.body.txn_type !== 'web_accept' && req.body.txn_type !== 'subscr_payment') ||
      !userId || !sponsorUntil
    ) {
      // Ignoring PayPal IPN
      return res.end();
    }
    // Processing PayPal IPN
    req.body.cmd = '_notify-validate';
    return new Promise((resolve, reject) => request.post({
      uri: PAYPAL_URI,
      form: req.body,
    }, (err, response, body) => {
      if (err) {
        reject(err);
      } else if (body !== 'VERIFIED') {
        reject(new Error('PayPal IPN unverified'));
      } else {
        resolve();
      }
    }))
      .then(() => exports.putUser(userId, {
        paypalEmail,
        sponsorUntil,
      }))
      .then(() => res.end());
  })
  .catch(next);

exports.checkSponsor = (idToken) => {
  if (!idToken) {
    return Promise.resolve(false);
  }
  return exports.getUserFromToken(idToken)
    .then(userInfo => userInfo && userInfo.sponsorUntil > Date.now(), () => false);
};

exports.checkMonetize = (token) => {
  if (!token) {
    return Promise.resolve(false);
  }
  return new Promise(resolve => request({
    uri: 'https://monetizejs.com/api/payments',
    qs: {
      access_token: token,
    },
    json: true,
  }, (err, paymentsRes, payments) => {
    const authorized = payments && payments.app === 'ESTHdCYOi18iLhhO' && (
      (payments.chargeOption && payments.chargeOption.alias === 'once') ||
      (payments.subscriptionOption && payments.subscriptionOption.alias === 'yearly'));
    resolve(!err && paymentsRes.statusCode === 200 && authorized);
  }));
};
