import type { PrintOption, PrintPdfOption } from './types'
export const printContainerId = 'custom-printer-container'
export const printFrameId = 'custom-printer-iframe'
export const printingClass = 'custom-printing'

/**
 * 创建并获取打印容器
 */
export function getPrintContainer(): Element {
  const container = document.getElementById(printContainerId)
  if (container) {
    return container
  }
  const elem = document.createElement('div')
  elem.id = printContainerId
  document.body.appendChild(elem)
  return elem
}

/**
 * 打印
 */
export function doPrint(option: PrintOption) {
  const $html = document.querySelector('html')
  if ($html) {
    $html.classList.add(printingClass)
    // 打印设置
    const elem = document.createElement('style')
    elem.setAttribute('type', 'text/css')
    elem.setAttribute('media', 'print')
    elem.innerHTML = getOptionCss(option)
    document.body.appendChild(elem)
    // 修改页面标题
    const title = document.title
    if (option.title != null && option.title !== '') {
      document.title = option.title
    }
    // 打印
    ;(window as any).print(option.options)
    // 打印结束
    $html.classList.remove(printingClass)
    document.body.removeChild(elem)
    // 恢复页面标题
    if (option.title != null) {
      document.title = title
    }
  }
}

/**
 * 在子窗口中打印
 */
export function doPrintOnFrame(opt: PrintOption) {
  const pFrame = getPrintFrame()
  const pWin = pFrame.contentWindow
  if (!pWin) {
    return
  }
  pWin.focus()
  const pDoc = pFrame.contentDocument || pWin.document
  if (!pDoc) {
    return
  }
  //
  const container = getPrintContainer()
  Array.from(container.querySelectorAll('input[type="text"], input[type="number"]')).forEach((el: any) => {
    el.setAttribute('value', el.value)
  })
  //
  pDoc.open()
  const printOption = opt.options ? `JSON.parse('${JSON.stringify(opt.options)}')` : ''
  const optHtml = `
  <style type="text/css" media="print">
    ${getOptionCss(opt)}
  </style>
  <script>
    const $html = document.querySelector('html');
    if($html && $html.classList && $html.classList.add) {
      $html.classList.add('${printingClass}');
    }
    window.onload = function() {
      if(${opt.title == null ? 0 : 1}) {
        document.title = '${opt.title}';
      }
      window.print(${printOption});
      window.parent.postMessage('customPrintDone_${opt.printId}', '*');
    };
  </script>
  `
  const html = document.querySelector('html')?.outerHTML || ''
  const content = html
    .replace(/<script/g, '<textarea style="display:none;" ')
    .replace(/<\/script>/g, '</textarea>')
    .replace(/<\/html>/, optHtml + '</html>')
  pDoc.write('<!DOCTYPE html>' + content)
  pDoc.close()
  return pWin
}

/**
 * 创建并获取打印子窗口
 */
export function getPrintFrame(): HTMLIFrameElement {
  removePrintFrame()
  const elem = document.createElement('iframe')
  elem.id = printFrameId
  elem.style.width = '0px'
  elem.style.height = '0px'
  elem.style.position = 'fixed'
  elem.style.visibility = 'hidden'
  document.body.appendChild(elem)
  elem.focus()
  return elem
}

/**
 * 移除打印子窗口
 */
export function removePrintFrame() {
  const pFrame = document.getElementById(printFrameId)
  if (pFrame && pFrame.parentNode) {
    pFrame.parentNode.removeChild(pFrame)
  }
}

/**
 * 生成打印设置的样式
 */
export function getOptionCss(opt: PrintOption) {
  const css = ['@page {']
  if (opt.margin != null && opt.margin !== '') {
    const v = typeof opt.margin === 'number' ? opt.margin + 'px' : opt.margin
    css.push(`margin: ${v};`)
  }
  if (opt.direction != null && opt.direction !== '') {
    css.push(`size: ${opt.direction};`)
  }
  if (opt.orientation != null && opt.orientation !== '') {
    css.push(`page-orientation: ${opt.orientation};`)
  }
  css.push('}')
  return css.join(' ')
}

/**
 * 合并打印方法参数
 * @param options 参数
 * @param userOptions 自定义参数
 */
export function mergeOptions(options?: any, userOptions?: any) {
  if (options == null) {
    return userOptions
  }
  return Object.assign({}, options, userOptions)
}

/**
 * usePrinter
 */
export function usePrinter(done: () => void) {
  const printId = Date.now() + ''
  const onMessage = (e: MessageEvent<any>) => {
    if (e.data === `customPrintDone_${printId}`) {
      removePrintFrame()
      done && done()
    }
  }
  window.addEventListener('message', onMessage)
  onBeforeUnmount(() => {
    window.removeEventListener('message', onMessage)
  })
  return { printId }
}

/**
 * 打印 pdf
 * @param option 打印参数
 */
export function printPdf(option: PrintPdfOption) {
  const pFrame: any = getPrintFrame()
  pFrame.onload = () => {
    const url = pFrame.getAttribute('src')
    if (url) {
      pFrame.focus()
      pFrame.contentWindow && pFrame.contentWindow.print(option.options)
      option.done && option.done()
      URL.revokeObjectURL(url)
    }
  }

  // 开始打印
  const doPrint = (buffer: ArrayBuffer) => {
    const blob = new window.Blob([buffer], { type: 'application/pdf' })
    // if (window.navigator && window.navigator['msSaveOrOpenBlob']) {
    //   window.navigator['msSaveOrOpenBlob'](blob, 'print.pdf')
    //   return
    // }
    pFrame.setAttribute('src', window.URL.createObjectURL(blob))
  }

  // 请求 pdf 数据
  if (option.arraybuffer) {
    doPrint(option.arraybuffer)
    return
  }
  if (option.url) {
    const req = new window.XMLHttpRequest()
    req.open('GET', option.url, true)
    req.responseType = 'arraybuffer'
    req.onload = () => {
      if ([200, 201].indexOf(req.status) !== -1) {
        doPrint(req.response)
        return
      }
      option.error && option.error(req.status, req.statusText)
    }
    req.send()
  }
}
