require('dotenv').config()
const express = require('express')
const bodyParser = require('body-parser')
const next = require('next')
const compression = require('compression')
const pick = require('lodash.pick')
const stripe = require('stripe')(process.env.STRIPE_SECRETE_KEY)

const endpointSecret = process.env.STRIPE_ENDPOINT_SECRET

const w = require('./lib/utils/w')
const createSucceededEmail = require('./lib/emails/payment-succeeded')
const {sendMail} = require('./lib/sendmail')

const port = process.env.PORT || 3001
const dev = process.env.NODE_ENV !== 'production'
const donProduct = process.env.STRIPE_DON_PRODUCT
const app = next({dev})
const handle = app.getRequestHandler()

app.prepare().then(() => {
  const server = express()
  server.use((req, res, next) => {
    if (req.originalUrl === '/stripe/valid-payment' || req.originalUrl === '/stripe/check-payment' || req.originalUrl === '/stripe/cancel-payment') {
      express.json()(req, res, next)
    } else {
      next()
    }
  })

  if (!dev) {
    server.use(compression())
  }

  server.get('/awtis', (req, res) => {
    res.redirect('/awtis/paj/1')
  })

  server.get('/awtis/paj/:paj', (req, res) => {
    app.render(req, res, '/awtis', {
      ...req.query,
      paj: req.params.paj
    })
  })

  // Stripe routes

  server.get('/stripe/dons-list', w(async (req, res) => {
    const prices = await stripe.prices.list({
      active: true,
      product: donProduct
    })
    const {data} = prices
    const filteredData = data.map(d => pick(d, ['id', 'unit_amount']))
    const sortedData = filteredData.sort((a, b) => a.unit_amount - b.unit_amount)
    res.send(sortedData)
  }))

  server.post('/stripe/valid-payment', w(async (req, res) => {
    let customer
    const {id, email} = req.body
    const price = await stripe.prices.retrieve(
      id
    )
    if (!price) {
      throw new Error('Une erreur s’est produite')
    }

    const customerSearch = await stripe.customers.list({
      email
    })

    if (customerSearch.data.length > 0) {
      customer = customerSearch.data.find(c => c.email === email)
    } else {
      customer = await stripe.customers.create({
        email
      })
    }

    if (!customer) {
      return res.sendStatus(400)
    }

    const paymentIntent = await stripe.paymentIntents.create({
      amount: price.unit_amount,
      currency: 'eur',
      automatic_payment_methods: {
        enabled: true
      },
      customer: customer.id,
      receipt_email: email,
      description: 'Don fait à Organisation KA Internationale'
    })

    res.send({
      clientSecret: paymentIntent.client_secret,
      paymentIntent: paymentIntent.id
    })
  }))

  server.post('/stripe/check-payment', w(async (req, res) => {
    const {payment_intent} = req.body
    const paymentFromStripe = await stripe.paymentIntents.retrieve(
      payment_intent
    )
    res.send(paymentFromStripe)
  }))

  server.post('/stripe/cancel-payment', w(async (req, res) => {
    const {paymentIntent} = req.body
    const paymentCanceled = await stripe.paymentIntents.cancel(paymentIntent, {
      cancellation_reason: 'abandoned'
    })

    if (!paymentCanceled) {
      res.sendStatus(404)
    }

    if (paymentCanceled.status === 'canceled') {
      res.sendStatus(200)
    } else {
      res.sendStatus(400)
    }
  }))

  server.post('/stripe/webhook', bodyParser.raw({type: 'application/json'}), async (req, res) => {
    let event = req.body
    if (endpointSecret) {
      const signature = req.headers['stripe-signature']
      try {
        event = stripe.webhooks.constructEvent(
          req.body,
          signature,
          endpointSecret
        )
      } catch (error) {
        console.log('⚠️  Webhook signature verification failed.', error.message)
        return res.sendStatus(400)
      }
    }

    const paymentIntent = event.data.object

    const email = createSucceededEmail(paymentIntent.amount / 100)
    switch (event.type) {
      case 'payment_intent.succeeded':
        await sendMail(email, paymentIntent.receipt_email)
        break

      default:
        console.log(`Unhandled event type ${event.type}`)
    }

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

  server.get('*', (req, res) => handle(req, res))

  server.post('*', (req, res) => handle(req, res))

  server.listen(port, error => {
    if (error) {
      throw error
    }
  })

  console.log(`> Ready on http://localhost:${port}`)
})
