import { patch } from 'jiff'
import { chain, findIndex, isNull } from 'lodash'
import { hasReadAccess } from '../../../utils/auth/access'
import { verifyIdToken } from '../../../utils/auth/firebaseAdmin'
import { createNodeBracePath } from '../../../utils/rgHelpers'

const { db, rg } = require('../../../utils/arangoWrapper')
const compoundEvents = db.collection(`compound_events`)

async function getReversedDiff(nid, eid, fctime, lctime) {
  const until = lctime + 0.0001
  const response = await rg.get('/event/diff', {
    path: `/n/${nid}`,
    reverse: true,
    since: fctime,
    until,
  })
  const result = response.body[0]
  const idx = findIndex(result.events, { _id: eid })

  return result.commands[idx]
}

const DiffAPI = async (req, res) => {
  const { token } = req.headers

  try {
    const claims = await verifyIdToken(token)
    const ukey = claims.uid
    const userId = `users/${ukey}`
    const { eid } = req.query
    const cEvent = await compoundEvents.document(eid)
    const { mid, event, fctime, lctime, nids, eids } = cEvent

    if (await hasReadAccess(mid, userId)) {
      let response, diff, nid, output, indexes, filteredNids, nKeys, path, timestamp

      switch (req.method) {
        case 'GET':
          output = {}

          switch (event) {
            case 'created':
            case 'restored':
              output.v1 = {}
              nid = nids.find((nid) => nid.startsWith('nodes/')) || mid
              response = await rg.get('/history/show', {
                path: `/n/${nid}`,
                timestamp: lctime,
              })
              output.v2 = response.body[0]

              break

            case 'deleted':
              indexes = chain(nids)
                .map((nid, idx) =>
                  /^(nodes|mindmaps)\//.test(nid) ? idx : null
                )
                .reject(isNull)
                .value()
              output.v2 = indexes.map(() => ({}))
              filteredNids = nids.filter((nid, idx) =>
                indexes.includes(idx)
              )

              nKeys = {}
              for (const nid of filteredNids) {
                const [coll, key] = nid.split('/')
                if (!nKeys[coll]) {
                  nKeys[coll] = []
                }
                nKeys[coll].push(key)
              }
              path = createNodeBracePath(nKeys)

              timestamp = fctime - 0.0001
              response = await rg.get('/history/show', { path, timestamp })
              output.v1 = response.body

              break

            case 'updated':
              nid = nids[0]
              response = await rg.get('/history/show', {
                path: `/n/${nid}`,
                timestamp: lctime,
              })
              output.v2 = response.body[0]

              diff = await getReversedDiff(nid, eids[0], fctime, lctime)
              output.v1 = patch(diff, response.body[0])
          }

          return res.status(200).json(output)
      }
    } else {
      return res.status(401).json({ message: 'Access Denied.' })
    }
  } catch (error) {
    console.error(error.message, error.stack)

    return res.status(401).json({ message: 'Access Denied.' })
  }
}

export default DiffAPI