import { TaskRegistry } from '@things-factory/integration-base'
import { PDFCaptureUtil, getCommonParameterSpec } from '@things-factory/integration-headless'
import { BoardFunc } from '@things-factory/board-service'
import { access } from '@things-factory/utils'
import { headlessModel } from './headless-model'

const PAGE_FORMATS = {
  A4: { width: 595.28, height: 841.89 },
  A3: { width: 841.89, height: 1190.55 },
  Letter: { width: 612, height: 792 },
  Legal: { width: 612, height: 1008 }
}

function convertToPixels(value: string): number {
  const dpi = 96 // PDF에서 기본적으로 사용하는 DPI

  if (value.endsWith('px')) {
    return parseFloat(value)
  } else if (value.endsWith('in')) {
    const inches = parseFloat(value)
    return inches * dpi
  } else if (value.endsWith('cm')) {
    const cm = parseFloat(value)
    return cm * (dpi / 2.54)
  }

  return 0
}

export async function HeadlessPDFCaptureProcess(step, context) {
  const pdfUtil = new PDFCaptureUtil(context)
  await pdfUtil.initBrowser(step.connection)

  try {
    var {
      process: processObject,
      accessor,
      processAccessor,
      draft,
      format = 'A4',
      width,
      height,
      landscape,
      marginLeft = 0,
      marginRight = 0,
      marginTop = 0,
      marginBottom = 0
    } = step.params
    var { domain, data, user, logger } = context

    const processId = processAccessor ? access(processAccessor, data) : processObject?.id

    if (!processId) {
      throw new Error('The process property must be set')
    }

    const processInput = access(accessor, data)

    const { model, base } = await headlessModel({ domain, id: processId }, draft)
    const [fontsToUse, fontStyles] = await BoardFunc.fonts(domain)

    model.fonts = fontsToUse
    model.fontStyles = fontStyles

    var widthN = width ? convertToPixels(width) : 0
    var heightN = height ? convertToPixels(height) : 0

    if (!widthN && !heightN && PAGE_FORMATS[format]) {
      const pageDimensions = PAGE_FORMATS[format]
      widthN = pageDimensions.width * (96 / 72)
      heightN = pageDimensions.height * (96 / 72)
    }

    if (landscape && widthN && heightN) {
      ;[widthN, heightN] = [heightN, widthN]
    }

    marginLeft = convertToPixels(marginLeft)
    marginTop = convertToPixels(marginTop)
    marginBottom = convertToPixels(marginBottom)
    marginRight = convertToPixels(marginRight)

    const contentWidth = widthN - marginLeft - marginRight
    const contentHeight = heightN - marginTop - marginBottom

    const page = await pdfUtil.browser!.newPage()

    await page.setViewport({ width: Math.round(contentWidth), height: Math.round(contentHeight) })
    await page.setRequestInterception(true)
    await page.setDefaultTimeout(10000)

    page.on('console', async msg => {
      console.log(`[browser ${msg.type()}] ${msg.text()}`)
    })

    page.on('requestfailed', request => {
      console.log('Request failed:', request.url())
    })

    const protocol = 'http'
    const host = 'localhost'
    const port = process.env.PORT ? `:${process.env.PORT}` : ''
    const path = '/internal-board-service-view'
    const url = `${protocol}://${host}${port}${path}`

    const token = await user?.sign()

    page.on('request', request => {
      if (request.url() === url) {
        request.continue({
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'x-things-factory-domain': domain?.subdomain,
            Authorization: 'Bearer ' + token
          },
          postData: JSON.stringify({
            model,
            base
          })
        })
      } else if (request.url().startsWith(`${protocol}://${host}${port}`)) {
        request.continue({
          headers: {
            ...request.headers(),
            'x-things-factory-domain': domain?.subdomain,
            Authorization: 'Bearer ' + token
          }
        })
      } else {
        request.continue()
      }
    })

    await page.goto(url)

    await page.evaluate(data => {
      //@ts-ignore
      s.data = data
      return new Promise(resolve => {
        requestAnimationFrame(() => resolve(0))
      })
    }, processInput)

    await pdfUtil.processPageAndGeneratePDF(step.params, null, page)

    return {
      data: context.__headless_pdf
    }
  } catch (error) {
    throw error
  } finally {
    await pdfUtil.closeBrowser()
  }
}

HeadlessPDFCaptureProcess.parameterSpec = [
  ...getCommonParameterSpec(),
  {
    type: 'string',
    name: 'processAccessor',
    label: 'process-accessor'
  },
  {
    type: 'resource-object',
    name: 'process',
    label: 'process',
    property: {
      queryName: 'processes'
    }
  },
  {
    type: 'boolean',
    name: 'draft',
    label: 'process-draft',
    defaultValue: false,
    description: 'Set whether to get the current working version or the last released version'
  }
]

HeadlessPDFCaptureProcess.help = 'integration/task/headless-pdf-capture-process'

TaskRegistry.registerTaskHandler('headless-pdf-capture-process', HeadlessPDFCaptureProcess)
