import got from 'got'

// Because we use shielding, it's recommended that you purge twice
// so it purges the edge nodes *and* the origin.
// The documentation says:
//
//    One solution to this race condition problem is simply to purge
//    twice. For purge-all operations, the two purges should be
//    around 30 seconds apart and, for single object and surrogate
//    key purges, around 2 seconds apart.
//
// See https://developer.fastly.com/learning/concepts/purging/#shielding
const DELAY_BEFORE_FIRST_PURGE = 0 * 1000
const DELAY_BEFORE_SECOND_PURGE = 2 * 1000

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))

async function purgeFastlyBySurrogateKey({ apiToken, serviceId, surrogateKey }) {
  const safeServiceId = encodeURIComponent(serviceId)

  const headers = {
    'fastly-key': apiToken,
    accept: 'application/json',
    'fastly-soft-purge': '1',
  }
  const requestPath = `https://api.fastly.com/service/${safeServiceId}/purge/${surrogateKey}`
  return got.post(requestPath, { headers, json: true })
}

export default async function purgeEdgeCache(
  surrogateKey,
  {
    purgeTwice = true,
    delayBeforeFirstPurge = DELAY_BEFORE_FIRST_PURGE,
    delayBeforeSecondPurge = DELAY_BEFORE_SECOND_PURGE,
  } = {},
) {
  if (!surrogateKey) {
    throw new Error('No key set and/or no FASTLY_SURROGATE_KEY env var set')
  }
  console.log(`Fastly purgeEdgeCache initialized for: '${surrogateKey}'`)

  const { FASTLY_TOKEN, FASTLY_SERVICE_ID } = process.env
  if (!FASTLY_TOKEN || !FASTLY_SERVICE_ID) {
    throw new Error('Fastly env vars not detected; skipping purgeEdgeCache step')
  }

  const purgingParams = {
    apiToken: FASTLY_TOKEN,
    serviceId: FASTLY_SERVICE_ID,
    surrogateKey,
  }

  // Give the app some extra time to wake up before the thundering herd of
  // Fastly requests.
  if (delayBeforeFirstPurge) {
    console.log('Waiting extra time to prevent a Thundering Herd problem...')
    await sleep(delayBeforeFirstPurge)
  }

  console.log('Attempting first Fastly purge...')
  const firstPurge = await purgeFastlyBySurrogateKey(purgingParams)
  console.log('First Fastly purge result:', firstPurge.body || firstPurge)

  // See comment above about why we purge twice. (Hint, it's shielding)
  if (purgeTwice) {
    console.log('Waiting to purge a second time...')
    await sleep(delayBeforeSecondPurge)

    console.log('Attempting second Fastly purge...')
    const secondPurge = await purgeFastlyBySurrogateKey(purgingParams)
    console.log('Second Fastly purge result:', secondPurge.body || secondPurge)
  }
}