import {
  BadRequest,
  NotAuthorized,
} from '../../../libs/api-v3/errors';
import amzLib from '../../../libs/api-v3/amazonPayments';
import {
  authWithHeaders,
  authWithUrl,
} from '../../../middlewares/api-v3/auth';
import shared from '../../../../../common';
import payments from '../../../libs/api-v3/payments';
import moment from 'moment';
import { model as Coupon } from '../../../models/coupon';
import { model as User } from '../../../models/user';
import cc from 'coupon-code';

let api = {};

/**
 * @apiIgnore Payments are considered part of the private API
 * @api {post} /amazon/verifyAccessToken Amazon Payments: verify access token
 * @apiVersion 3.0.0
 * @apiName AmazonVerifyAccessToken
 * @apiGroup Payments
 *
 * @apiSuccess {Object} data Empty object
 **/
api.verifyAccessToken = {
  method: 'POST',
  url: '/amazon/verifyAccessToken',
  middlewares: [authWithHeaders()],
  async handler (req, res) {
    let accessToken = req.body.access_token;

    if (!accessToken) throw new BadRequest('Missing req.body.access_token');

    await amzLib.getTokenInfo(accessToken);
    res.respond(200, {});
  },
};

/**
 * @apiIgnore Payments are considered part of the private API
 * @api {post} /amazon/createOrderReferenceId Amazon Payments: create order reference id
 * @apiVersion 3.0.0
 * @apiName AmazonCreateOrderReferenceId
 * @apiGroup Payments
 *
 * @apiSuccess {string} data.orderReferenceId The order reference id.
 **/
api.createOrderReferenceId = {
  method: 'POST',
  url: '/amazon/createOrderReferenceId',
  middlewares: [authWithHeaders()],
  async handler (req, res) {
    let billingAgreementId = req.body.billingAgreementId;

    if (!billingAgreementId) throw new BadRequest('Missing req.body.billingAgreementId');

    let response = await amzLib.createOrderReferenceId({
      Id: billingAgreementId,
      IdType: 'BillingAgreement',
      ConfirmNow: false,
    });

    res.respond(200, {
      orderReferenceId: response.OrderReferenceDetails.AmazonOrderReferenceId,
    });
  },
};

/**
 * @apiIgnore Payments are considered part of the private API
 * @api {post} /amazon/checkout Amazon Payments: checkout
 * @apiVersion 3.0.0
 * @apiName AmazonCheckout
 * @apiGroup Payments
 *
 * @apiSuccess {object} data Empty object
 **/
api.checkout = {
  method: 'POST',
  url: '/amazon/checkout',
  middlewares: [authWithHeaders()],
  async handler (req, res) {
    let gift = req.body.gift;
    let user = res.locals.user;
    let orderReferenceId = req.body.orderReferenceId;
    let amount = 5;

    if (!orderReferenceId) throw new BadRequest('Missing req.body.orderReferenceId');

    if (gift) {
      if (gift.type === 'gems') {
        amount = gift.gems.amount / 4;
      } else if (gift.type === 'subscription') {
        amount = shared.content.subscriptionBlocks[gift.subscription.key].price;
      }
    }

    await amzLib.setOrderReferenceDetails({
      AmazonOrderReferenceId: orderReferenceId,
      OrderReferenceAttributes: {
        OrderTotal: {
          CurrencyCode: 'USD',
          Amount: amount,
        },
        SellerNote: 'HabitRPG Payment',
        SellerOrderAttributes: {
          SellerOrderId: shared.uuid(),
          StoreName: 'HabitRPG',
        },
      },
    });

    await amzLib.confirmOrderReference({ AmazonOrderReferenceId: orderReferenceId });

    await amzLib.authorize({
      AmazonOrderReferenceId: orderReferenceId,
      AuthorizationReferenceId: shared.uuid().substring(0, 32),
      AuthorizationAmount: {
        CurrencyCode: 'USD',
        Amount: amount,
      },
      SellerAuthorizationNote: 'HabitRPG Payment',
      TransactionTimeout: 0,
      CaptureNow: true,
    });

    await amzLib.closeOrderReference({ AmazonOrderReferenceId: orderReferenceId });

    // execute payment
    let method = 'buyGems';
    let data = { user, paymentMethod: 'Amazon Payments' };

    if (gift) {
      if (gift.type === 'subscription') method = 'createSubscription';
      gift.member = await User.findById(gift ? gift.uuid : undefined);
      data.gift = gift;
      data.paymentMethod = 'Gift';
    }

    await payments[method](data);

    res.respond(200);
  },
};

/**
 * @apiIgnore Payments are considered part of the private API
 * @api {post} /amazon/subscribe Amazon Payments: subscribe
 * @apiVersion 3.0.0
 * @apiName AmazonSubscribe
 * @apiGroup Payments
 *
 * @apiSuccess {object} data Empty object
 **/
api.subscribe = {
  method: 'POST',
  url: '/amazon/subscribe',
  middlewares: [authWithHeaders()],
  async handler (req, res) {
    let billingAgreementId = req.body.billingAgreementId;
    let sub = req.body.subscription ? shared.content.subscriptionBlocks[req.body.subscription] : false;
    let coupon = req.body.coupon;
    let user = res.locals.user;

    if (!sub) throw new BadRequest(res.t('missingSubscriptionCode'));
    if (!billingAgreementId) throw new BadRequest('Missing req.body.billingAgreementId');

    if (sub.discount) { // apply discount
      if (!coupon) throw new BadRequest(res.t('couponCodeRequired'));
      let result = await Coupon.findOne({_id: cc.validate(coupon), event: sub.key});
      if (!result) throw new NotAuthorized(res.t('invalidCoupon'));
    }

    await amzLib.setBillingAgreementDetails({
      AmazonBillingAgreementId: billingAgreementId,
      BillingAgreementAttributes: {
        SellerNote: 'HabitRPG Subscription',
        SellerBillingAgreementAttributes: {
          SellerBillingAgreementId: shared.uuid(),
          StoreName: 'HabitRPG',
          CustomInformation: 'HabitRPG Subscription',
        },
      },
    });

    await amzLib.confirmBillingAgreement({
      AmazonBillingAgreementId: billingAgreementId,
    });

    await amzLib.authorizeOnBillingAgreement({
      AmazonBillingAgreementId: billingAgreementId,
      AuthorizationReferenceId: shared.uuid().substring(0, 32),
      AuthorizationAmount: {
        CurrencyCode: 'USD',
        Amount: sub.price,
      },
      SellerAuthorizationNote: 'HabitRPG Subscription Payment',
      TransactionTimeout: 0,
      CaptureNow: true,
      SellerNote: 'HabitRPG Subscription Payment',
      SellerOrderAttributes: {
        SellerOrderId: shared.uuid(),
        StoreName: 'HabitRPG',
      },
    });

    await payments.createSubscription({
      user,
      customerId: billingAgreementId,
      paymentMethod: 'Amazon Payments',
      sub,
    });

    res.respond(200);
  },
};

/**
 * @apiIgnore Payments are considered part of the private API
 * @api {get} /amazon/subscribe/cancel Amazon Payments: subscribe cancel
 * @apiVersion 3.0.0
 * @apiName AmazonSubscribe
 * @apiGroup Payments
 **/
api.subscribeCancel = {
  method: 'GET',
  url: '/amazon/subscribe/cancel',
  middlewares: [authWithUrl],
  async handler (req, res) {
    let user = res.locals.user;
    let billingAgreementId = user.purchased.plan.customerId;

    if (!billingAgreementId) throw new NotAuthorized(res.t('missingSubscription'));

    await amzLib.closeBillingAgreement({
      AmazonBillingAgreementId: billingAgreementId,
    });

    await payments.cancelSubscription({
      user,
      nextBill: moment(user.purchased.plan.lastBillingDate).add({ days: 30 }),
      paymentMethod: 'Amazon Payments',
    });

    if (req.query.noRedirect) {
      res.respond(200);
    } else {
      res.redirect('/');
    }
  },
};

module.exports = api;
