/* eslint-disable camelcase */
/* eslint-disable max-len */
/*
import nconf from 'nconf';
import moment from 'moment';
import util from 'util';
import _ from 'lodash';
import paypalIpn from 'pp-ipn';
import paypal from 'paypal-rest-sdk';
import cc from 'coupon-code';
import shared from '../../../common';
import payments from './payments'; // eslint-disable-line import/no-cycle
import { getGemsBlock, validateGiftMessage } from './gems'; // eslint-disable-line import/no-cycle
import { model as Coupon } from '../../models/coupon';
import { model as User } from '../../models/user'; // eslint-disable-line import/no-cycle
import { // eslint-disable-line import/no-cycle
  model as Group,
  basicFields as basicGroupFields,
} from '../../models/group';
import {
  BadRequest,
  NotAuthorized,
  NotFound,
} from '../errors';

const BASE_URL = nconf.get('BASE_URL');
const PAYPAL_MODE = nconf.get('PAYPAL_MODE');
const { i18n } = shared;

// This is the plan.id for paypal subscriptions.
// You have to set up billing plans via their REST sdk (they don't have
// a web interface for billing-plan creation), see ./paypalBillingSetup.js for how.
// After the billing plan is created
// there, get it's plan.id and store it in config.json
_.each(shared.content.subscriptionBlocks, block => {
  block.paypalKey = nconf.get(`PAYPAL_BILLING_PLANS_${block.key}`);
});

paypal.configure({
  mode: PAYPAL_MODE, // sandbox or live
  client_id: nconf.get('PAYPAL_CLIENT_ID'),
  client_secret: nconf.get('PAYPAL_CLIENT_SECRET'),
});

const experienceProfileId = nconf.get('PAYPAL_EXPERIENCE_PROFILE_ID');

// TODO better handling of errors
// @TODO: Create constants

const api = {};

api.constants = {
  // CURRENCY_CODE: 'USD',
  // SELLER_NOTE: 'Habitica Payment',
  // SELLER_NOTE_SUBSCRIPTION: 'Habitica Subscription',
  // SELLER_NOTE_ATHORIZATION_SUBSCRIPTION: 'Habitica Subscription Payment',
  // STORE_NAME: 'Habitica',
  //
  // GIFT_TYPE_GEMS: 'gems',
  // GIFT_TYPE_SUBSCRIPTION: 'subscription',
  //
  // METHOD_BUY_GEMS: 'buyGems',
  // METHOD_CREATE_SUBSCRIPTION: 'createSubscription',
  PAYMENT_METHOD: 'Paypal',
  // PAYMENT_METHOD_GIFT: 'Amazon Payments (Gift)',
};

api.paypalPaymentCreate = util.promisify(paypal.payment.create.bind(paypal.payment));
api.paypalPaymentExecute = util.promisify(paypal.payment.execute.bind(paypal.payment));
api.paypalBillingAgreementCreate = util
  .promisify(paypal.billingAgreement.create.bind(paypal.billingAgreement));
api.paypalBillingAgreementExecute = util
  .promisify(paypal.billingAgreement.execute.bind(paypal.billingAgreement));
api.paypalBillingAgreementGet = util
  .promisify(paypal.billingAgreement.get.bind(paypal.billingAgreement));
api.paypalBillingAgreementCancel = util
  .promisify(paypal.billingAgreement.cancel.bind(paypal.billingAgreement));

api.ipnVerifyAsync = util.promisify(paypalIpn.verify.bind(paypalIpn));

api.checkout = async function checkout (options = {}) {
  const {
    gift, gemsBlock: gemsBlockKey, sku, user,
  } = options;

  let amount;
  let gemsBlock;
  let description = 'Habitica Gems';

  if (gift) {
    const member = await User.findById(gift.uuid).exec();
    gift.member = member;

    validateGiftMessage(gift, user);

    if (gift.type === 'gems') {
      if (gift.gems.amount <= 0) {
        throw new BadRequest(i18n.t('badAmountOfGemsToPurchase'));
      }
      amount = Number(gift.gems.amount / 4).toFixed(2);
      description = `${description} (Gift)`;
    } else {
      amount = Number(shared.content.subscriptionBlocks[gift.subscription.key].price).toFixed(2);
      description = 'mo. Habitica Subscription (Gift)';
    }
  } else if (sku) {
    if (sku === 'Pet-Gryphatrice-Jubilant') {
      description = 'Jubilant Gryphatrice';
      amount = 9.99;
    }
  } else {
    gemsBlock = getGemsBlock(gemsBlockKey);
    amount = gemsBlock.price / 100;
  }

  if (gemsBlock || (gift && gift.type === 'gems')) {
    const receiver = gift ? gift.member : user;
    const receiverCanGetGems = await receiver.canGetGems();
    if (!receiverCanGetGems) throw new NotAuthorized(shared.i18n.t('groupPolicyCannotGetGems', receiver.preferences.language));
  }

  const createPayment = {
    intent: 'sale',
    payer: { payment_method: this.constants.PAYMENT_METHOD },
    redirect_urls: {
      return_url: `${BASE_URL}/paypal/checkout/success`,
      cancel_url: `${BASE_URL}`,
    },
    transactions: [{
      item_list: {
        items: [{
          name: description,
          // sku: 1,
          price: amount,
          currency: 'USD',
          quantity: 1,
        }],
      },
      amount: {
        currency: 'USD',
        total: amount,
      },
      description,
    }],
  };

  if (experienceProfileId) {
    createPayment.experience_profile_id = experienceProfileId;
  }

  const result = await this.paypalPaymentCreate(createPayment);
  const link = _.find(result.links, { rel: 'approval_url' }).href;
  return link;
};

api.checkoutSuccess = async function checkoutSuccess (options = {}) {
  const {
    user, gift, gemsBlock: gemsBlockKey, paymentId, customerId, sku,
  } = options;

  let method = sku ? 'buySkuItem' : 'buyGems';
  const data = {
    user,
    customerId,
    paymentMethod: this.constants.PAYMENT_METHOD,
  };

  if (gift) {
    gift.member = await User.findById(gift.uuid).exec();
    if (gift.type === 'subscription') {
      method = 'createSubscription';
    }

    data.paymentMethod = 'PayPal (Gift)';
    data.gift = gift;
  } else if (sku) {
    data.sku = sku;
  } else {
    data.gemsBlock = getGemsBlock(gemsBlockKey);
  }

  await this.paypalPaymentExecute(paymentId, { payer_id: customerId });
  await payments[method](data);
};

api.subscribe = async function subscribe (options = {}) {
  const { sub, coupon } = options;

  if (sub.discount) {
    if (!coupon) throw new BadRequest(i18n.t('couponCodeRequired'));
    const couponResult = await Coupon.findOne({ _id: cc.validate(coupon), event: sub.key }).exec();
    if (!couponResult) throw new NotAuthorized(i18n.t('invalidCoupon'));
  }

  const billingPlanTitle = `Habitica Subscription ($${sub.price} every ${sub.months} months, recurring)`;
  const billingAgreementAttributes = {
    name: billingPlanTitle,
    description: billingPlanTitle,
    start_date: moment().add({ minutes: 5 }).format(),
    plan: {
      id: sub.paypalKey,
    },
    payer: {
      payment_method: this.constants.PAYMENT_METHOD,
    },
  };
  const billingAgreement = await this.paypalBillingAgreementCreate(billingAgreementAttributes);

  const link = _.find(billingAgreement.links, { rel: 'approval_url' }).href;
  return link;
};

api.subscribeSuccess = async function subscribeSuccess (options = {}) {
  const {
    user, groupId, block, headers, token,
  } = options;
  const result = await this.paypalBillingAgreementExecute(token, {});
  await payments.createSubscription({
    user,
    groupId,
    customerId: result.id,
    paymentMethod: this.constants.PAYMENT_METHOD,
    sub: block,
    headers,
  });
};
*/
/**
 * Cancel a PayPal Subscription
 *
 * @param  options
 * @param  options.user  The user object who is canceling
 * @param  options.groupId  The id of the group that is canceling
 * @param  options.cancellationReason  A text string to control sending an email
 *
 * @return undefined
 */
/*
api.subscribeCancel = async function subscribeCancel (options = {}) {
  const { groupId, user, cancellationReason } = options;

  let customerId;
  if (groupId) {
    const groupFields = basicGroupFields.concat(' purchased');
    const group = await Group.getGroup({
      user, groupId, populateLeader: false, groupFields,
    });

    if (!group) {
      throw new NotFound(i18n.t('groupNotFound'));
    }

    if (group.leader !== user._id) {
      throw new NotAuthorized(i18n.t('onlyGroupLeaderCanManageSubscription'));
    }
    customerId = group.purchased.plan.customerId;
  } else {
    customerId = user.purchased.plan.customerId;
  }

  if (!customerId) throw new NotAuthorized(i18n.t('missingSubscription'));

  const customer = await this.paypalBillingAgreementGet(customerId);

  // @TODO: Handle error response
  const nextBillingDate = customer.agreement_details.next_billing_date;
  if (customer.agreement_details.cycles_completed === '0') { // hasn't billed yet
    throw new BadRequest(i18n.t('planNotActive', { nextBillingDate }));
  }

  await this.paypalBillingAgreementCancel(customerId, { note: i18n.t('cancelingSubscription') });
  await payments.cancelSubscription({
    user,
    groupId,
    paymentMethod: this.constants.PAYMENT_METHOD,
    nextBill: nextBillingDate,
    cancellationReason,
  });
};

api.ipn = async function ipnApi (options = {}) {
  await this.ipnVerifyAsync(options, {
    allow_sandbox: PAYPAL_MODE === 'sandbox',
  });

  const { txn_type, recurring_payment_id } = options;

  const ipnAcceptableTypes = [
    'recurring_payment_profile_cancel',
    'recurring_payment_failed',
    'recurring_payment_expired',
    'subscr_cancel',
    'subscr_failed',
  ];

  if (ipnAcceptableTypes.indexOf(txn_type) === -1) return;

  // @TODO: Should this request billing date?
  const user = await User.findOne({ 'purchased.plan.customerId': recurring_payment_id }).exec();
  if (user) {
    // If the user has already cancelled the subscription, return
    // Otherwise the subscription would be cancelled twice
    // resulting in the loss of subscription credits
    if (user.hasCancelled()) return;

    await payments.cancelSubscription({ user, paymentMethod: this.constants.PAYMENT_METHOD });
    return;
  }

  const groupFields = basicGroupFields.concat(' purchased');
  const group = await Group
    .findOne({ 'purchased.plan.customerId': recurring_payment_id })
    .select(groupFields)
    .exec();

  if (group) {
    // If the group subscription has already been cancelled the subscription, return
    // Otherwise the subscription would be cancelled
    // twice resulting in the loss of subscription credits
    if (group.hasCancelled()) return;

    await payments.cancelSubscription({
      groupId: group._id,
      paymentMethod: this.constants.PAYMENT_METHOD,
    });
  }
};

export default api;
*/
