import { chromium, Browser, Page } from 'playwright'
import type { PDFTemplateData } from './types'

export class PDFRenderer {
  private browser: Browser | null = null
  private browserStartTime: number = 0
  private readonly MAX_BROWSER_LIFETIME = 3600000
  private readonly MAX_BROWSER_MEMORY = 536870912

  async initialize(): Promise<void> {
    if (!this.browser) {
      this.browser = await chromium.launch({ headless: true })
      this.browserStartTime = Date.now()
    }
  }

  async renderPDF(html: string, timeout_ms: number = 30000): Promise<Buffer> {
    await this.initialize()

    if (!this.browser) {
      throw new Error('Browser not initialized')
    }

    const page = await this.browser.newPage()

    try {
      await page.setContent(html, { waitUntil: 'networkidle' })

      const pdfBuffer = await page.pdf({
        format: 'A4',
        margin: { top: '0', right: '0', bottom: '0', left: '0' },
        timeout: timeout_ms,
      })

      return pdfBuffer
    } finally {
      await page.close()
      await this.checkBrowserHealth()
    }
  }

  private async checkBrowserHealth(): Promise<void> {
    if (!this.browser) return

    const now = Date.now()
    const lifetime = now - this.browserStartTime

    if (lifetime > this.MAX_BROWSER_LIFETIME) {
      console.log('[PDFRenderer] Browser lifetime exceeded, restarting...')
      await this.restartBrowser()
    }
  }

  private async restartBrowser(): Promise<void> {
    if (this.browser) {
      await this.browser.close()
    }
    this.browser = null
    await this.initialize()
  }

  async close(): Promise<void> {
    if (this.browser) {
      await this.browser.close()
      this.browser = null
    }
  }
}

export function renderTemplate(html: string, data: PDFTemplateData): string {
  let rendered = html

  Object.entries(data).forEach(([key, value]) => {
    if (Array.isArray(value)) {
      const itemsHtml = value.map(item => {
        const itemHtml = html.match(new RegExp(`{{#each ${key}}}(.*?){{/each}}`, 's'))
        if (itemHtml && itemHtml[1]) {
          return itemHtml[1].replace('{{this}}', String(item))
        }
        return ''
      }).join('')

      rendered = rendered.replace(
        new RegExp(`{{#each ${key}}}.*?{{/each}}`, 's'),
        itemsHtml
      )
    } else if (typeof value === 'object') {
      Object.entries(value).forEach(([nested, nestedValue]) => {
        rendered = rendered.replace(
          new RegExp(`{{${key}\\.${nested}}}`, 'g'),
          String(nestedValue)
        )
      })
    } else {
      rendered = rendered.replace(new RegExp(`{{${key}}}`, 'g'), String(value))
    }
  })

  return rendered
}
