import paypal from '@paypal/checkout-server-sdk';
import assert from "assert";
import { paypal_private } from "../lib/config.js";
import { Product, Payment } from "../lib/models.js";
import { product_id } from "../client/config.js";
import logging from "../lib/logging.js";
import { developer_admin } from "../lib/api.js";

const log = logging.create("queue/paypal.js");


const create_paypal = () => {
  if(developer_admin) {
    log.warn("Running in DANGER_ADMIN mode so using the Sandbox for Paypal.");
    const environment = new paypal.core.SandboxEnvironment(paypal_private.client_id, paypal_private.secret);

    const client = new paypal.core.PayPalHttpClient(environment);

    return [environment, client];
  } else {
    const environment = new paypal.core.LiveEnvironment(paypal_private.client_id, paypal_private.secret);

    const client = new paypal.core.PayPalHttpClient(environment);

    return [environment, client];
  }
}

const [environment, client] = create_paypal();

const order_is_valid = (course, response, payment) => {
  let order = response.result.purchase_units[0];

  assert(course.id, "Product is invalid in order_is_valid check.");
  assert(payment.id, "Payment is invalid in order_is_valid check.");

  if(!order) {
    log.error(`Invalid response payment ${payment.id}, no order in the purchase_units.`);
    return [false, "invalid_purchase_units"];
  } else if(parseInt(order.amount.value, 10) !== course.price) {
    // BUG: this will fail if you use a float for the price
    log.error(`Wrong price ${order.amount.value}`);
    return [false, "invalid_order_amount"];
  } else if(order.payments.captures.length < 1) {
    log.error("Not enough captures, only 0.");
    return [false, "invalid_capture_count"];
  } else if(order.payments.captures[0].status !== "COMPLETED") {
    log.error(`Capture not completed: ${order.payments.captures.status}`);
    return [false, "capture_not_completed"];
  } else if(parseInt(order.payments.captures[0].amount.value, 10) !== course.price) {
    console.error(`Capture amount ${order.payments.captures[0].amount.value} doesn't match course price ${course.price}`);
    return [false, "capture_price_mismatch"];
  } else {
    return [true, "validated"];
  }
}

export const validate_order = async (job) => {
  try {
    assert(job.data.payment_id, `Invalid order ID: ${JSON.stringify(job)}`);

    const course = await Product.first({id: product_id});
    assert(course, `No course for ID ${ product_id } from client/config.js:product_id`);

    const payment = await Payment.first({id: job.data.payment_id});
    assert(payment, `No payment for ID ${ job.payment_id }`);

    let request = new paypal.orders.OrdersGetRequest(payment.sys_primary_id);

    // Call API with your client and get a response for your call
    let response = await client.execute(request);

    log.debug(`Validating Paypal ID ${response.result.id}`);

    const [valid, status_reason] = order_is_valid(course, response, payment);

    if(valid) {
      log.info(`Order for payment ${payment.id} is validated.`);
      await Payment.update({id: payment.id}, {status: "complete", status_reason});
    } else {
      log.error(`Invalid Order for payment ${payment.id}.`);
      await Payment.update({id: payment.id}, {status: "failed", status_reason});
    }
  } catch(error) {
    log.error(error, `Processing payment paypal verification for ${job.data.payment_id}`);

    try {
      await Payment.update({id: job.data.payment_id}, {status: "failed", status_reason: "check_logs"});
    } catch (e) {
      log.error(error, `Failed to update the database with failure on payment id ${job.data.payment_id}`);
    }
  }
}
