import Taro from '@tarojs/taro'
import { View, Camera, Button, Canvas, RichText, Text } from '@tarojs/components'

import classNames from 'classnames'
import PropTypes, { InferProps } from 'prop-types'
import CtsComponent from '../../common/component'
import { CtsTakePhotoProps, CtsTakePhotoState } from 'types/take-photo'

const borderMarginTop = 400 // 扫描框顶部距离

/**
 * 拍照组件
 */
export default class CtsTakePhoto extends CtsComponent<CtsTakePhotoProps, CtsTakePhotoState> {
  public static defaultProps: CtsTakePhotoProps
  public static propTypes: InferProps<CtsTakePhotoProps>

  public constructor(props: CtsTakePhotoProps) {
    super(props)
    this.state = {
      cWidth: 0,
      cHeight: 0,
      bHeight: 0
    }
  }

  public componentWillReceiveProps(props: CtsTakePhotoProps): void {
    const { show } = props
    if (show) {
      // 获取拍照边框的属性
      setTimeout(() => {
        this.getDom()
      }, 500)
    }
  }

  // 用户不允许使用摄像头时触发
  private cameraError(e) {
    console.log('camera error：', e.detail)
  }

  // 获取拍照边框的属性
  private getDom(): void {
    console.log(Taro.getSystemInfoSync())

    // 计算拍照边框的高度
    let { windowWidth } = Taro.getSystemInfoSync()
    Taro.createSelectorQuery()
      .in(this.$scope)
      .selectAll('#border')
      .boundingClientRect((res: any) => {
        console.log('current createSelectorQuery ', res)

        if (res.length) {
          let { width } = res[0]

          const bHeight = ((width / 1.5) * 750) / windowWidth
          console.log('bHeight：', bHeight)

          this.setState({
            bHeight
          })
        }
      })
      .exec()
  }

  // 点击显示拍照
  // take(idcardType) {
  //   this.setState({
  //     show: true,
  //     idcardType
  //   }, () => {
  //     // 获取拍照边框的属性
  //     this.getDom()
  //   })
  // }

  // 拍照
  private takePhoto(): void {
    Taro.showLoading({ title: '加载中...', mask: true })

    const { bizCode } = this.props

    const that = this
    const ctx = Taro.createCameraContext()

    ctx.takePhoto({
      quality: 'high',
      success(res: any) {
        console.log('takePhoto：', res)

        let { tempImagePath: file, width: cWidth, height: cHeight } = res
        let { windowWidth, windowHeight } = Taro.getSystemInfoSync()

        let borderWidth = cWidth * 0.8 // 扫描框宽度
        let borderHeight = borderWidth / 1.5 // 扫描框高度
        let borderLeft = (cWidth - borderWidth) / 2 // 扫描框离左边的距离
        // let borderTop = (cHeight - borderHeight) / 2 // 扫描框离顶部的距离
        let borderTop = ((borderMarginTop / 750) * windowWidth) / (windowHeight / cHeight) // 扫描框离顶部的距离（先把borderMarginTop（rpx）转化为px单位，在相对于屏幕高度windowHeight:照片高度cHeight，计算裁剪的位置离顶部的距离borderTop）


        that.setState({
          cWidth,
          cHeight
        })

        // 绘制图形并取出图片路径
        let ctx = Taro.createCanvasContext('canvas', that)

        // 绘制图像到画布
        ctx.drawImage(file, borderLeft, borderTop, borderWidth, borderHeight, 0, 0, cWidth, cHeight)
        // ctx.drawImage(file, 0, 0, cWidth, cHeight)

        // 将之前在绘图上下文中的描述（路径，变形，样式）画到cavnas中
        ctx.draw(false, () => {
          setTimeout(() => {
            // takePhoto下可能会失败（canvasToTempFilePath:fail:create bitmap failed，canvasToTempFilePath:fail:create bitmap failed）（失败几率：10%，原因暂时未找到，解决办法：使用递归调用解决）
            let i = 0 // 递归调用次数，次数超过10次则重新要求拍照
            tempFilePath()
            function tempFilePath() {
              // 把当前画布制定区域的内容导出生成制定大小的图片。在draw()回调里调用该方法才能保证图片导出成功
              Taro.canvasToTempFilePath(
                {
                  canvasId: 'canvas', // 画布标识，传入canvas组件的canvas-id
                  destWidth: borderWidth, // 输出的图片的宽度
                  destHeight: borderHeight, // 输出的图片的高度
                  fileType: 'jpg', // 目标文件的类型，jpg，png
                  quality: 1, // 图片的质量，目前仅对jpg有效，取值范围为(0,1]，不在范围内时当作1.0处理
                  success(res) {
                    console.log('压缩后的图片：', res) // 最终图片路径

                    // 上传附件返回url
                    const params = { file: res.tempFilePath, sysCode: Taro['common'].apiLink.replace('/', ''), bizCode }
                    Taro['common'].uploadFile(params).then(res => {
                      // console.log('上传文件成功返回值：', res)

                      that.props.onTakePhoto(res.data)

                      Taro.hideLoading()
                    })
                  },
                  fail(err) {
                    console.log('压缩图片失败：', i, err)

                    if (i < 10) {
                      tempFilePath()
                      i++
                    } else {
                      Taro.showToast({ title: '图片模糊，请重拍...', icon: 'none' })
                      i = 0
                    }
                  }
                },
                that.$scope
              )
            }
          }, 200)
        })
      }
    })
  }

  // 上传身份证正反面
  chooseImage() {
    const { bizCode } = this.props

    let that = this;
    // 从本地相册选择图片或使用相机拍照
    Taro.chooseImage({
      count: 1,
      sizeType: ['compressed'],
      sourceType: ['album', 'camera'],
      success(res) {
        console.log('从本地相册选择图片或使用相机拍照：', res)

        let { path: file, size }: any = res.tempFiles[0]

        // 获取图片信息，网络图片需先配置download域名才能生效
        Taro.getImageInfo({
          src: file,
          success(res) {
            console.log('getImageInfo', res)

            let cWidth = res.width
            let cHeight = res.height

            // 图片超过2M就压缩
            if (size <= 2 * 1024 * 1024) {
              that.setState({
                cWidth,
                cHeight
              })

              // 上传附件返回url
              const params = {
                file,
                sysCode: Taro['common'].apiLink.replace('/', ''),
                bizCode
              }
              Taro['common'].uploadFile(params).then(res => {
                console.log('上传文件成功返回值：', res)

                that.props.onTakePhoto(res.data)
              })
              return
            }

            // 利用canvas压缩图片
            let ratio = Math.round(size / 1024 / 1024) // 压缩强度，根据图片大小计算

            cWidth = Math.trunc(res.width / ratio)
            cHeight = Math.trunc(res.height / ratio)

            that.setState({
              cWidth,
              cHeight
            })

            console.log('压缩图片的宽和高：', size, ratio, cWidth, cHeight)

            // 绘制图形并取出图片路径
            let ctx = Taro.createCanvasContext('canvas', that)

            // 绘制图像到画布
            ctx.drawImage(res.path, 0, 0, cWidth, cHeight)

            // 将之前在绘图上下文中的描述（路径，变形，样式）画到cavnas中
            ctx.draw(false, () => {
              setTimeout(() => {
                // 把当前画布制定区域的内容导出生成制定大小的图片。在draw()回调里调用该方法才能保证图片导出成功
                Taro.canvasToTempFilePath({
                  canvasId: 'canvas', // 画布标识，传入canvas组件的canvas-id
                  destWidth: cWidth, // 输出的图片的宽度
                  destHeight: cHeight, // 输出的图片的高度
                  fileType: 'jpg', // 目标文件的类型，jpg，png
                  quality: 1, // 图片的质量，目前仅对jpg有效，取值范围为(0,1]，不在范围内时当作1.0处理
                  success(res) {
                    console.log('压缩后的图片：', res) // 最终图片路径

                    // 上传附件返回url
                    const params = {
                      file: res.tempFilePath,
                      sysCode: Taro['common'].apiLink.replace('/', ''),
                      bizCode
                    }
                    Taro['common'].uploadFile(params).then(res => {
                      console.log('上传文件成功返回值：', res)

                      that.props.onTakePhoto(res.data)
                    })

                  },
                  fail(err) {
                    console.log(err)
                  }
                }, that.$scope)
              }, 100)
            })
          },
          fail(err) {
            console.log(err)
          }
        })
      }
    })
  }

  public render(): JSX.Element | null {
    const { className, show, note1, note2, onCancel } = this.props
    const { cWidth, cHeight, bHeight } = this.state

    return show ? (
      <View className={classNames('cts-take-photo', className)}>
        <Camera device-position="back" flash="off" onError={this.cameraError.bind(this)} style="width: 100%; height: 100%;"></Camera>

        <View className="camera-border">
          <View className="camera-border-home" id="border" style={{ marginTop: Taro.pxTransform(borderMarginTop), height: Taro.pxTransform(bHeight), visibility: bHeight ? 'visible' : 'hidden' }}></View>
        </View>

        <View className="camera-tip">
          <View className="camera-home">
            <View className="note top">
              <RichText nodes={note1}></RichText>
            </View>
            <View className="note bottom">
              <RichText nodes={note2}></RichText>
            </View>

            <View className="camera-btn">
              <Button onClick={onCancel}>取消</Button>
              <Button onClick={this.takePhoto.bind(this)} type="primary">
                拍照
              </Button>
            </View>
          </View>
        </View>

        <Text className='at-icon at-icon-image' onClick={this.chooseImage.bind(this)}></Text>

        <Canvas canvasId="canvas" style={{ width: cWidth + 'px', height: cHeight + 'px', position: 'absolute', top: Taro.pxTransform(-10000) }}></Canvas>
      </View>
    ) : null
  }
}

CtsTakePhoto.defaultProps = {
  show: false,
  note1: '',
  note2: '',
  bizCode: '',
  onTakePhoto() {},
  onCancel() {}
}

CtsTakePhoto.propTypes = {
  show: PropTypes.bool,
  note1: PropTypes.string,
  note2: PropTypes.string,
  bizCode: PropTypes.string,
  onTakePhoto: PropTypes.func,
  onCancel: PropTypes.func
}
