import { Payment } from '../../lib/models.js';
import logging from '../../lib/logging.js';
import { API, defer } from "../../lib/api.js";
import fetch from 'node-fetch';
import { btcpay_private } from '../../lib/config.js';
import { product_id, fake_payments, register_enabled } from '../../client/config.js';
import { Product } from "../../lib/models.js";
import assert from "assert";

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

const rules = {
  amount: "required|numeric|min:0|max:100",
}

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

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

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

  try {
    assert(!fake_payments, "You have fake_payments set so use /api/user/payment APIs.");
    assert(!btcpay_private.disabled, "BTC Payments are disabled in secrets/config.json.");

    const form = api.validate(rules);
    assert(form.amount === product.price, `Form amount ${form.amount} doesn't match course price ${product.price}`);

    if(form._valid) {
      let internal_id = Payment.gen_internal_id();

      const options = {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': btcpay_private.auth
        },
        body: JSON.stringify({
          "amount": form.amount,
          "currency": product.currency,
          "checkout": {
            "speedPolicy": "HighSpeed"
          },
          "metadata": {
            "orderId": internal_id,
            "itemDesc": product.description,
          }
        }),
      }

      const response = await fetch(`${btcpay_private.url}/invoices`, options);
      const text = await response.text();

      if(response.status != 200) {
        log.info(`BTCPAY error: ${response.status}, text: '${text}'`);
        return api.error(403, 'BTCPay server failure');
      } else {
        const data = JSON.parse(text);
        const sys_primary_id = data.id;

        let payment = await Payment.insert({
          system: 'btcpay',
          status: 'pending',
          user_id: api.user.id,
          internal_id,
          sys_primary_id,
          sys_created_on: new Date(data.createdTime)
        });

        assert(payment, "Failed to store payment in the database. Email help@learnjsthehardway.com.");

        return api.reply(200, {sys_primary_id, internal_id});
      }
    } else {
      log.error(form._errors, "btcpay validation failure");
      return api.validation_error(res, form);
    }
  } catch(error) {
    log.error(error);
    return api.error(403, 'BTCPay server failure');
  }
}

get.authenticated = true;

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

  try{
    log.debug(`btcpay POST Recieved message ${JSON.stringify(msg)}`);

    const options = {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': btcpay_private.auth
      },
    }

    let response = await fetch(`${btcpay_private.url}/invoices/${msg.sys_primary_id}`, options);
    let data = await response.json();

    // TODO: what are the error conditions on this response?

    let waiter = defer("settled_waiting");
    setTimeout(() => waiter.resolve(), 5000);
    await waiter;

    response = await fetch(`${btcpay_private.url}/invoices/${msg.sys_primary_id}`, options);
    data = await response.json();
    // TODO: what are the error conditions on this response?

    console.log("BTCPAY COMPLETE WITH", data);

    const sys_primary_id = data.id;
    const status = data.status;
    const btc_due = data.btcDue;

    // BUG: this doesn't seem to actually mark it complete
    if(status == 'paid') {
      let count = await Payment.update({
        sys_primary_id,
        internal_id: msg.internal_id
      }, {status: 'complete'});

      assert(count === 1, "Failed to update payment database.");
    }

    api.reply(200, {sys_primary_id, status, btc_due});
  } catch(error) {
    log.error(error);
    api.error(403, 'Failed to confirm payment');
  }
}

post.authenticated = true;
