import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
import { groupBy, keyBy } from 'lodash'
import { getValues, log, payUser, writeAsync } from './utils'
import { Bet } from '../../common/bet'
import { Contract } from '../../common/contract'
import { PortfolioMetrics, User } from '../../common/user'
import { getLoanUpdates } from '../../common/loans'
import { createLoanIncomeNotification } from './create-notification'

const firestore = admin.firestore()

export const updateLoans = functions
  .runWith({ memory: '2GB', timeoutSeconds: 540 })
  // Run every Monday.
  .pubsub.schedule('0 0 * * 1')
  .timeZone('America/Los_Angeles')
  .onRun(updateLoansCore)

async function updateLoansCore() {
  log('Updating loans...')

  const [users, contracts, bets] = await Promise.all([
    getValues<User>(firestore.collection('users')),
    getValues<Contract>(
      firestore.collection('contracts').where('isResolved', '==', false)
    ),
    getValues<Bet>(firestore.collectionGroup('bets')),
  ])
  log(
    `Loaded ${users.length} users, ${contracts.length} contracts, and ${bets.length} bets.`
  )
  const userPortfolios = await Promise.all(
    users.map(async (user) => {
      const portfolio = await getValues<PortfolioMetrics>(
        firestore
          .collection(`users/${user.id}/portfolioHistory`)
          .orderBy('timestamp', 'desc')
          .limit(1)
      )
      return portfolio[0]
    })
  )
  log(`Loaded ${userPortfolios.length} portfolios`)
  const portfolioByUser = keyBy(userPortfolios, (portfolio) => portfolio.userId)

  const contractsById = Object.fromEntries(
    contracts.map((contract) => [contract.id, contract])
  )
  const betsByUser = groupBy(bets, (bet) => bet.userId)
  const { betUpdates, userPayouts } = getLoanUpdates(
    users,
    contractsById,
    portfolioByUser,
    betsByUser
  )

  log(`${betUpdates.length} bet updates.`)

  const betDocUpdates = betUpdates.map((update) => ({
    doc: firestore
      .collection('contracts')
      .doc(update.contractId)
      .collection('bets')
      .doc(update.betId),
    fields: {
      loanAmount: update.loanTotal,
    },
  }))

  await writeAsync(firestore, betDocUpdates)

  log(`${userPayouts.length} user payouts`)

  await Promise.all(
    userPayouts.map(({ user, payout }) => payUser(user.id, payout))
  )

  const today = new Date().toDateString().replace(' ', '-')
  const key = `loan-notifications-${today}`
  await Promise.all(
    userPayouts.map(({ user, payout }) =>
      createLoanIncomeNotification(user, key, payout)
    )
  )

  log('Notifications sent!')
}