import * as admin from 'firebase-admin'
import Stripe from 'stripe'

import { EndpointDefinition } from './api'
import { getPrivateUser, getUser, isProd, payUser } from './utils'
import { sendThankYouEmail } from './emails'
import { track } from './analytics'

export type StripeSession = Stripe.Event.Data.Object & {
  id: string
  metadata: {
    userId: string
    manticDollarQuantity: string
  }
}

export type StripeTransaction = {
  userId: string
  manticDollarQuantity: number
  sessionId: string
  session: StripeSession
  timestamp: number
}

const initStripe = () => {
  const apiKey = process.env.STRIPE_APIKEY as string
  return new Stripe(apiKey, { apiVersion: '2020-08-27', typescript: true })
}

// manage at https://dashboard.stripe.com/test/products?active=true
const manticDollarStripePrice = isProd()
  ? {
      500: 'price_1KFQXcGdoFKoCJW770gTNBrm',
      1000: 'price_1KFQp1GdoFKoCJW7Iu0dsF65',
      2500: 'price_1KFQqNGdoFKoCJW7SDvrSaEB',
      10000: 'price_1KFQraGdoFKoCJW77I4XCwM3',
    }
  : {
      500: 'price_1K8W10GdoFKoCJW7KWORLec1',
      1000: 'price_1K8bC1GdoFKoCJW76k3g5MJk',
      2500: 'price_1K8bDSGdoFKoCJW7avAwpV0e',
      10000: 'price_1K8bEiGdoFKoCJW7Us4UkRHE',
    }

export const createcheckoutsession: EndpointDefinition = {
  opts: { method: 'POST', minInstances: 1, secrets: ['STRIPE_APIKEY'] },
  handler: async (req, res) => {
    const userId = req.query.userId?.toString()

    const manticDollarQuantity = req.query.manticDollarQuantity?.toString()

    if (!userId) {
      res.status(400).send('Invalid user ID')
      return
    }

    if (
      !manticDollarQuantity ||
      !Object.keys(manticDollarStripePrice).includes(manticDollarQuantity)
    ) {
      res.status(400).send('Invalid Mantic Dollar quantity')
      return
    }

    const referrer =
      req.query.referer || req.headers.referer || 'https://manifold.markets'

    const stripe = initStripe()
    const session = await stripe.checkout.sessions.create({
      metadata: {
        userId,
        manticDollarQuantity,
      },
      line_items: [
        {
          price:
            manticDollarStripePrice[
              manticDollarQuantity as unknown as keyof typeof manticDollarStripePrice
            ],
          quantity: 1,
        },
      ],
      mode: 'payment',
      success_url: `${referrer}?funding-success`,
      cancel_url: `${referrer}?funding-failiure`,
    })

    res.redirect(303, session.url || '')
  },
}

export const stripewebhook: EndpointDefinition = {
  opts: {
    method: 'POST',
    minInstances: 1,
    secrets: ['MAILGUN_KEY', 'STRIPE_APIKEY', 'STRIPE_WEBHOOKSECRET'],
  },
  handler: async (req, res) => {
    const stripe = initStripe()
    let event

    try {
      // Cloud Functions jam the raw body into a special `rawBody` property
      const rawBody = (req as any).rawBody ?? req.body
      event = stripe.webhooks.constructEvent(
        rawBody,
        req.headers['stripe-signature'] as string,
        process.env.STRIPE_WEBHOOKSECRET as string
      )
    } catch (e: any) {
      console.log(`Webhook Error: ${e.message}`)
      res.status(400).send(`Webhook Error: ${e.message}`)
      return
    }

    if (event.type === 'checkout.session.completed') {
      const session = event.data.object as StripeSession
      await issueMoneys(session)
    }

    res.status(200).send('success')
  },
}

const issueMoneys = async (session: StripeSession) => {
  const { id: sessionId } = session

  const query = await firestore
    .collection('stripe-transactions')
    .where('sessionId', '==', sessionId)
    .get()

  if (!query.empty) {
    console.log('session', sessionId, 'already processed')
    return
  }

  const { userId, manticDollarQuantity } = session.metadata
  const payout = Number.parseInt(manticDollarQuantity)

  const transaction: StripeTransaction = {
    userId,
    manticDollarQuantity: payout, // save as number
    sessionId,
    session,
    timestamp: Date.now(),
  }

  await firestore.collection('stripe-transactions').add(transaction)

  await payUser(userId, payout, true)
  console.log('user', userId, 'paid M$', payout)

  const user = await getUser(userId)
  if (!user) return

  const privateUser = await getPrivateUser(userId)
  if (!privateUser) return

  await sendThankYouEmail(user, privateUser)

  await track(
    userId,
    'M$ purchase',
    { amount: payout, sessionId },
    { revenue: payout / 100 }
  )
}

const firestore = admin.firestore()