import { Product, Payment } from '../../lib/models.js';
import { API, developer_admin } from "../../lib/api.js";
import logging from '../../lib/logging.js';
import dayjs from 'dayjs';
import { product_id, register_enabled } from "../../client/config.js";
import assert from 'assert';
import * as queues from "../../lib/queues.js";
import stripe_create from "stripe";
import { stripe_private } from "../../lib/config.js";

const log = logging.create("api/payments/stripe.js");

const stripe = stripe_create(stripe_private.secret);

const product = await Product.first({id: product_id});

const rules = {
  "payment_intent": "required",
  "payment_intent_client_secret": "required",
  "redirect_status": "required"
};

const create_stripe_payment = async (user) => {
  assert(product.price > 1, "Stripe requires the price to be greater than $1.");

  const intent = await stripe.paymentIntents.create({
    amount: product.price * 100,
    currency: product.currency.toLowerCase(),
    automatic_payment_methods: {
      enabled: true,
    },
  });

  assert(intent, "Failed to create stripe intent.");

  let internal_id = Payment.gen_internal_id();

  // TODO: see if we can use date-fns instead of dayjs here
  let payment = await Payment.insert({
    user_id: user.id,
    system: 'stripe',
    status: 'pending',
    status_reason: "started",
    internal_id,
    sys_primary_id: intent.id,
    sys_secondary_id: intent.client_secret,
    sys_created_on: new Date()
  });

  assert(payment && payment.internal_id, "Failed to save payment.");

  return [intent, payment];
}

export const post = async (req, res) => {
  const api = new API(req, res);

  if(!register_enabled) {
    return api.error(500, {errors: { main: "Registration is disabled."}});
  }

  try {
    let clientSecret;

    const pending = await Payment.first({user_id: api.user.id, status: "pending", system: "stripe"});

    if(pending) {
      // this already exists so send back the original secret
      clientSecret = pending.sys_secondary_id;
    } else {
      // this is a new request so create it
      const [intent, payment] = await create_stripe_payment(api.user);
      clientSecret = intent.client_secret;
    }

    api.reply(200, { clientSecret });
  } catch(error) {
    log.error(error);
    api.error(500, "Fatal error in the server. Tell Zed.");
  }
}

post.authenticated = true;

export const get = async (req, res) => {
  const api = new API(req, res);

  if(!register_enabled) {
    return api.error(500, {errors: { main: "Registration is disabled."}});
  }

  try {
    const msg = api.validate(rules);

    if(!msg._valid) {
      log.error(msg._errors, "Stripe validation failure");
      return api.validation_error(res, msg);
    } if(msg.redirect_status === "succeeded") {
      // find the user's payment attempt using the stripe id
      let payment = await Payment.first({
        user_id: api.user.id,
        system: "stripe",
        sys_primary_id: msg.payment_intent
      });

      // redirect status is succeeded so this is complete
      await Payment.update({id: payment.id}, {status: "complete"});

      // send out all of the emails and everything
      queues.send_welcome(api.user);
      queues.send_receipt(api.user, payment.id, product.id);

      // downside to stripe is they do a redirect to finish
      return api.redirect("/client/#/payment/finished/");
    } else {
      // need to handle the other stripe redirect states
      log.debug("STRIPE ERROR", msg);
      return api.error(402, `Stripe error: ${JSON.stringify(msg)}`);
    }
  } catch(error) {
    log.error(error);
    return api.error(403, 'Stripe configuration failed');
  }
}

get.authenticated = true;
