import { dom } from 'kit_utils';

import styles from './index.less';

class SlideVerify {

    init() {
        this.initDOM()
        this.initImg()
        this.bindEvents()
    }
    render({container, onSuccess, onFail, onRefresh}) {
        container.style.position = container.style.position || 'relative'
        this.slideLong = 42 // 拼图边长
        this.slideRadius = 9 // 拼图缺口半径
        this.canvasWidth = 310  // canvas宽度
        this.canvasHeight = 155   // canvas高度
        this.slideTotalWidth = this.slideLong + this.slideRadius * 2 + 3   // 拼图实际边长
        this.container = container
        this.onSuccess = onSuccess
        this.onFail = onFail
        this.onRefresh = onRefresh
        this.init()
    }
    destroy() {
        const childs = this.container.childNodes;
        for(let i = childs .length - 1; i >= 0; i--) {
            this.container.removeChild(childs[i]);
        }
    }
    initDOM () {
        var canvas = this.createCanvas(this.canvasWidth, this.canvasHeight) // 画布
        var block = canvas.cloneNode(true) // 拼图
        var sliderContainer = this.createElement('div', styles.sliderContainer)
        var refreshIcon = this.createElement('div', styles.refreshIcon)
        var sliderMask = this.createElement('div', styles.sliderMask)
        var slider = this.createElement('div', styles.slider)
        var sliderIcon = this.createElement('span', styles.sliderIcon)
        var text = this.createElement('span', styles.sliderText)
  
        block.className = styles.sliderBlock
        text.innerHTML = '向右滑动填充拼图'
  
        var el = this.container
        el.appendChild(canvas)
        el.appendChild(refreshIcon)
        el.appendChild(block)
        slider.appendChild(sliderIcon)
        sliderMask.appendChild(slider)
        sliderContainer.appendChild(sliderMask)
        sliderContainer.appendChild(text)
        el.appendChild(sliderContainer)
       
        Object.assign(this, {
            canvas,
            block,
            sliderContainer,
            refreshIcon,
            slider,
            sliderMask,
            sliderIcon,
            text,
            canvasCtx: canvas.getContext('2d'),
            blockCtx: block.getContext('2d')
        })
    }

    initImg () {
        var img = this.createImg(() => {
            this.startDraw()
            this.canvasCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight)
            this.blockCtx.drawImage(img, 0, 0, this.canvasWidth, this.canvasHeight)
            var y = this.slideY - this.slideRadius * 2 - 2
            var ImageData = this.blockCtx.getImageData(this.slideX - 3, y, this.slideTotalWidth, this.slideTotalWidth)
            this.block.width = this.slideTotalWidth
            this.blockCtx.putImageData(ImageData, 0, y)
        })
        this.img = img
    }

    startDraw () {
        // 随机创建拼图的位置(矩形拼图左上顶点位置)
        this.slideX = this.getRandomNumberByRange(this.slideTotalWidth + 10, this.canvasWidth - (this.slideTotalWidth + 10))
        this.slideY = this.getRandomNumberByRange(10 + this.slideRadius * 2, this.canvasHeight - (this.slideTotalWidth + 10))
        this.draw(this.canvasCtx, this.slideX, this.slideY, 'fill')
        this.draw(this.blockCtx, this.slideX, this.slideY, 'clip')
        
    }


    clean () {
        this.canvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
        this.blockCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
        this.block.width = this.canvasWidth
    }

    bindEvents () {
        this.container.onselectstart = () => false
        this.refreshIcon.onclick = () => {
            this.reset()
            typeof this.onRefresh === 'function' && this.onRefresh()
        }
  
        var originX, originY, trail = [], isMouseDown = false
  
        var handleDragStart = function (e) {
            originX = e.clientX || e.touches[0].clientX
            originY = e.clientY || e.touches[0].clientY
            isMouseDown = true
        }
  
        var handleDragMove = (e) => {
            if (!isMouseDown) return false
            var eventX = e.clientX || e.touches[0].clientX
            var eventY = e.clientY || e.touches[0].clientY
            var moveX = eventX - originX
            var moveY = eventY - originY
            if (moveX < 0 || moveX + 38 >= this.canvasWidth) return false
            this.slider.style.left = moveX + 'px'   //按钮的滑动距离
            var blockLeft = (this.canvasWidth - 40 - 20) / (this.canvasWidth - 40) * moveX  //按钮与滑块的移动比例相同
            this.block.style.left = blockLeft + 'px'
            dom.addClass(this.sliderContainer, styles['sliderContainer_active'])
            this.sliderMask.style.width = moveX + 'px'
            trail.push(moveY)
        }
  
        var handleDragEnd = (e) => {
            if (!isMouseDown) return false
            isMouseDown = false
            var eventX = e.clientX || e.changedTouches[0].clientX
            if (eventX == originX) return false
            dom.removeClass(this.sliderContainer, styles['sliderContainer_active'])
            this.trail = trail
            var { spliced, verified } = this.verify()
            if (spliced) {
                if (verified) {
                    dom.addClass(this.sliderContainer, styles['sliderContainer_success'])
                    typeof this.onSuccess === 'function' && this.onSuccess()
                } else {
                    dom.addClass(this.sliderContainer, styles['sliderContainer_fail'])
                    this.text.innerHTML = '再试一次'
                    this.reset()
                }
            } else {
                dom.addClass(this.sliderContainer, styles['sliderContainer_fail'])
                typeof this.onFail === 'function' && this.onFail()
                setTimeout(() => {
                    this.reset()
                }, 1000)
            }
        }
        this.slider.addEventListener('mousedown', handleDragStart)
        this.slider.addEventListener('touchstart', handleDragStart)
        document.addEventListener('mousemove', handleDragMove)
        document.addEventListener('touchmove', handleDragMove)
        document.addEventListener('mouseup', handleDragEnd)
        document.addEventListener('touchend', handleDragEnd)
    }

    verify () {
        const arr = this.trail // 拖动时y轴的移动距离
        const average = arr.reduce(this.sum) / arr.length
        const deviations = arr.map(x => x - average)
        const stddev = Math.sqrt(deviations.map(this.square).reduce(this.sum) / arr.length) //总体标准差
        const left = parseInt(this.block.style.left)
        return {
            spliced: Math.abs(left - this.slideX) < 10,
            verified: stddev !== 0, // 简单验证下拖动轨迹，为零时表示Y轴上下没有波动，可能非人为操作
        }
    }

    reset () {
        this.sliderContainer.className = styles.sliderContainer
        this.slider.style.left = 0
        this.block.style.left = 0
        this.sliderMask.style.width = 0
        this.clean()
        this.img.src = this.getRandomImg()
    }

    createCanvas(width, height) {
        const canvas = this.createElement('canvas')
        canvas.width = width
        canvas.height = height
        return canvas;
    }

    createElement(tagName, className) {
        const element = document.createElement(tagName)
        element.className = className
        return element
    }

    getRandomNumberByRange (start, end) {
        return Math.round(Math.random() * (end - start) + start)
    }

    getRandomImg () {
        return   require(`../../assets/SlideVerify/` + [this.getRandomNumberByRange(1, 8) + '.jpg'])
    }

    createImg (onload) {
        const img = new Image()
        img.setAttribute('crossOrigin', 'Anonymous')
        img.src = this.getRandomImg()
        img.onload = onload
        img.onerror = () => {
            img.src = this.getRandomImg()
        }
        
        return img
    }

    draw (ctx, x, y, operation) {
        const l = this.slideLong // 滑块边长
        const r = this.slideRadius
        const PI = Math.PI
        const borderGap = 2
        ctx.beginPath()
        ctx.moveTo(x, y)
        ctx.arc(x + l / 2, y - r + borderGap, r, 0.72 * PI, 2.26 * PI)  //上圆
        ctx.lineTo(x + l, y)
        ctx.arc(x + l + r - borderGap, y + l / 2, r, 1.21 * PI, 2.78 * PI)  //右圆
        ctx.lineTo(x + l, y + l)
        ctx.lineTo(x, y + l)
        ctx.arc(x + r - borderGap, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true)  //左圆
        ctx.lineTo(x, y)
        ctx.lineWidth = borderGap
        ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'
        ctx.strokeStyle = 'rgba(255, 255, 255, 0.7)'
        ctx.stroke()
        ctx[operation]()
        ctx.globalCompositeOperation = 'overlay'
    }
   
    sum (x, y) {
        return x + y
    }
   
    square (x) {
        return x * x
    }





}


export default SlideVerify;