import { env } from '@blocklet/sdk/lib/env';
import express, { NextFunction, Request, Response, Router } from 'express';
import get from 'lodash/get';

import handleStripeEvent from '../../integrations/stripe/handlers';
import logger from '../../libs/logger';
import { STRIPE_EVENTS } from '../../libs/util';
import { PaymentMethod } from '../../store/models';

const router = Router();

const verifyWebhookSig = async (req: Request, res: Response, next: NextFunction) => {
  try {
    const signature = req.get('stripe-signature');
    if (!signature) {
      return res.status(400).json({ error: 'No stripe webhook signature found' });
    }

    const json = JSON.parse(req.body.toString('utf8'));
    const method = await PaymentMethod.findOne({ where: { type: 'stripe', livemode: json.livemode } });
    if (!method) {
      return res.status(400).json({ error: 'No stripe payment method found' });
    }

    const stripe = method.getStripeClient();
    const settings = PaymentMethod.decryptSettings(method.settings);
    const secret = process.env.STRIPE_WEBHOOK_SECRET || settings.stripe?.webhook_signing_secret;
    req.stripeEvent = stripe.webhooks.constructEvent(req.body, signature, secret as string);
    req.stripeClient = stripe;

    return next();
  } catch (err) {
    logger.error('verify signature error', { error: err });
    return res.status(400).json({ error: err.message });
  }
};

const handleEvent = async (req: Request, res: Response) => {
  const { stripeEvent, stripeClient } = req;

  if (STRIPE_EVENTS.includes(stripeEvent.type) === false) {
    logger.debug('webhook event not interested', { id: stripeEvent.id, type: stripeEvent.type });
    return res.json({ skipped: true });
  }

  // only events from this app should be processed
  const appPid = get(stripeEvent, 'data.object.metadata.appPid');
  if (appPid && appPid !== env.appPid) {
    logger.debug('webhook event for other app', { id: stripeEvent.id, type: stripeEvent.type });
    return res.json({ skipped: true });
  }

  logger.debug('webhook received event', { id: stripeEvent.id, type: stripeEvent.type });
  await handleStripeEvent(stripeEvent, stripeClient);

  return res.json({ received: true });
};

router.post('/webhook', express.raw({ type: 'application/json' }), verifyWebhookSig, handleEvent);

export default router;
