import './style.less'

import classnames from 'classnames'
import React, { PureComponent } from 'react'

import { PAD_RATIO, PHONE_RATIO } from '../common'
import { loadImage } from '../utils'

interface ImgItem {
  src: string
  height: number
  width?: number
  divInner?: boolean
}

export interface Props {
  list?: Array<ImgItem>
  img?: ImgItem
  useDivInner?: boolean
  pxToRem?: boolean
  className?: string
  isPad?: boolean
  width?: number
  replace?: boolean
  onClick?: (e: any, imgItem: ImgItem, index: number) => void
  onSuccess?: () => void
  onFailure?: () => void
}

function getDPR() {
  let dpr = Math.floor(window.devicePixelRatio) || 1
  if (dpr > 3) dpr = 3
  if (dpr < 1) dpr = 1
  return dpr
}

export default class Picture extends PureComponent<Props, object> {
  public static defaultProps = {
    pxToRem: true
  }

  public container: HTMLDivElement | null = null
  public dpr = getDPR()

  public componentDidMount() {
    this.initImage()
  }

  public componentWillUnmount() {
    this.container = null
  }

  public initImage() {
    const { img, list, onSuccess, onFailure } = this.props
    const imgList = img ? [img] : list
    let sequence: any = Promise.resolve()
    ;(imgList as Array<ImgItem>).forEach((listItem: ImgItem, index: number) => {
      sequence = sequence.then(() => {
        return this.createImage(listItem, index)
      })
    })
    sequence.then(onSuccess, onFailure)
  }

  public createImage(listItem: ImgItem, index: number) {
    const { dpr, props, container } = this
    const {
      onClick,
      useDivInner,
      pxToRem,
      isPad,
      width: superWidth,
      replace
    } = props
    const { width: itemWidth, height, divInner, src } = listItem

    const isDivInner = typeof divInner === 'undefined' ? useDivInner : divInner
    const ratio = isPad ? PAD_RATIO : PHONE_RATIO
    const heightString = pxToRem ? `${height / ratio}rem` : `${height}px`
    const width = itemWidth || superWidth
    const widthString = width && pxToRem ? `${width / ratio}rem` : `${width}px`

    return new Promise((resolve, reject) => {
      if (!container) return

      const box = document.createElement('div')
      box.className = 'imager-container'
      box.style.height = heightString
      if (widthString) box.style.width = widthString
      container.appendChild(box)

      if (onClick) {
        box.addEventListener('click', event => {
          onClick(event, listItem, index)
        })
      }

      const nodeType = isDivInner ? 'div' : 'img'
      const imgEl = document.createElement(nodeType)
      imgEl.className = 'imager-inner'

      const resource = new Image()
      const miniImg = `${src}?imageView2/2/h/${height}`
      const suitableImg =
        dpr === 3 ? src : `${src}?imageView2/2/h/${height * dpr}`

      resource.onload = () => {
        box.style.backgroundImage = `url(${miniImg})`

        const suitableImgLoader = replace
          ? loadImage(suitableImg)
          : Promise.resolve({})

        suitableImgLoader.then(() => {
          if (isDivInner) {
            imgEl.style.backgroundImage = `url(${suitableImg})`
          } else {
            const el = imgEl as HTMLImageElement
            el.src = suitableImg
            el.style.height = heightString
            if (widthString) el.style.width = widthString
          }
          if (box) box.appendChild(imgEl)
          if (replace) box.style.backgroundImage = ''
        })

        resolve()
      }
      resource.onerror = err => {
        reject(err)
      }

      resource.src = miniImg
    })
  }

  public render() {
    const { className, isPad } = this.props
    return (
      <div
        ref={el => (this.container = el)}
        className={classnames('ph-picture', className, { 'is-pad': isPad })}
      />
    )
  }
}
