import express from 'express'
import puppeteer from 'puppeteer'

const captureUrl = process.env.CAPTURE_URL || 'http://host.docker.internal:3000/'
const port = process.env.PORT || 5678
const maxPages = Number(process.env.MAX_PAGES) || 5
const timeout = Number(process.env.TIMEOUT) || 10000
const cache = process.env.CACHE || 60000
const width = process.env.WIDTH || 600
const height = process.env.HEIGHT || 315
const deviceScaleFactor = process.env.SCALE_FACTOR || 2
// from https://www.bannerbear.com/blog/ways-to-speed-up-puppeteer-screenshots/
const args = [
  '--autoplay-policy=user-gesture-required',
  '--disable-background-networking',
  '--disable-background-timer-throttling',
  '--disable-backgrounding-occluded-windows',
  '--disable-breakpad',
  '--disable-client-side-phishing-detection',
  '--disable-component-update',
  '--disable-default-apps',
  '--disable-dev-shm-usage',
  '--disable-domain-reliability',
  '--disable-extensions',
  '--disable-features=AudioServiceOutOfProcess',
  '--disable-hang-monitor',
  '--disable-ipc-flooding-protection',
  '--disable-notifications',
  '--disable-offer-store-unmasked-wallet-cards',
  '--disable-popup-blocking',
  '--disable-print-preview',
  '--disable-prompt-on-repost',
  '--disable-renderer-backgrounding',
  '--disable-setuid-sandbox',
  '--disable-speech-api',
  '--disable-sync',
  '--hide-scrollbars',
  '--ignore-gpu-blacklist',
  '--metrics-recording-only',
  '--mute-audio',
  '--no-default-browser-check',
  '--no-first-run',
  '--no-pings',
  '--no-sandbox',
  '--no-zygote',
  '--password-store=basic',
  '--use-gl=swiftshader',
  '--use-mock-keychain'
]

let browser
const app = express()

app.get('/health', (req, res) => {
  res.status(200).end()
})

app.get('/*', async (req, res) => {
  const url = new URL(req.originalUrl, captureUrl)
  const timeLabel = `${Date.now()}-${url.href}`

  const urlParams = new URLSearchParams(url.search)
  const commentId = urlParams.get('commentId')

  let page, pages

  try {
    console.time(timeLabel)
    browser ||= await puppeteer.launch({
      headless: 'new',
      useDataDir: './data',
      executablePath: 'google-chrome-stable',
      args,
      protocolTimeout: timeout,
      defaultViewport: { width, height, deviceScaleFactor }
    })

    pages = (await browser.pages()).length
    console.timeLog(timeLabel, 'capturing', 'current pages', pages)

    // limit number of active pages
    if (pages > maxPages + 1) {
      console.timeLog(timeLabel, 'too many pages')
      return res.writeHead(503, {
        'Retry-After': 1
      }).end()
    }

    page = await browser.newPage()
    await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }])
    await page.goto(url.href, { waitUntil: 'load', timeout })
    console.timeLog(timeLabel, 'page loaded')

    if (commentId) {
      console.timeLog(timeLabel, 'scrolling to comment')
      await page.waitForSelector('.outline-it')
      await new Promise((resolve, _reject) => setTimeout(resolve, 100))
    }

    const file = await page.screenshot({ type: 'png', captureBeyondViewport: false })
    console.timeLog(timeLabel, 'screenshot complete')
    res.setHeader('Content-Type', 'image/png')
    res.setHeader('Cache-Control', `public, max-age=${cache}, immutable, stale-while-revalidate=${cache * 24}, stale-if-error=${cache * 24}`)
    return res.status(200).end(file)
  } catch (err) {
    console.timeLog(timeLabel, 'error', err)
    return res.status(500).end()
  } finally {
    console.timeEnd(timeLabel, 'pages at start', pages)
    page?.close().catch(console.error)
  }
})

app.listen(port, () =>
  console.log(`Screenshot listen on http://:${port}`)
)