// @ts-nocheck
// nvue 需要在节点上设置ref或在export里传入
// const animation = createAnimation({
//   ref: this.$refs['xxx'],
// 	 duration: 0,
// 	 timingFunction: 'linear'
// })
// animation.opacity(1).translate(x, y).step({duration})
// animation.export(ref)

// 抹平nvue 与 uni.createAnimation的使用差距
// 但是nvue动画太慢



import { CreateAnimationOptions } from './type'
// #ifdef APP-NVUE
const nvueAnimation = uni.requireNativePlugin('animation')

type AnimationTypes = 'matrix' | 'matrix3d' | 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY' | 'scaleZ' | 'skew' | 'skewX' | 'skewY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'translateZ'
	| 'opacity' | 'backgroundColor' | 'width' | 'height' | 'left' | 'right' | 'top' | 'bottom'

interface Styles {
	[key : string] : any
}
	
interface StepConfig {
	duration?: number
	timingFunction?: string
	delay?: number
	needLayout?: boolean
	transformOrigin?: string
}
interface StepAnimate {
	styles?: Styles
	config?: StepConfig
}
interface StepAnimates {
	[key: number]: StepAnimate
}
// export interface CreateAnimationOptions extends UniApp.CreateAnimationOptions {
// 	ref?: string
// }

type Callback = (time: number) => void
const animateTypes1 : AnimationTypes[] = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
	'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
	'translateZ'
]
const animateTypes2 : AnimationTypes[] = ['opacity', 'backgroundColor']
const animateTypes3 : AnimationTypes[] = ['width', 'height', 'left', 'right', 'top', 'bottom']

class LimeAnimation {
	ref : any
	context : any
	options : UniApp.CreateAnimationOptions
	// stack : any[] = []
	next : number = 0
	currentStepAnimates : StepAnimates = {}
	duration : number = 0
	constructor(options : CreateAnimationOptions) {
		const {ref} = options
		this.ref = ref
		this.options = options
	}
	addAnimate(type : AnimationTypes, args: (string | number)[]) {
		let aniObj = this.currentStepAnimates[this.next]
		let stepAnimate:StepAnimate = {}
		if (!aniObj) {
			stepAnimate = {styles: {}, config: {}}
		} else {
			stepAnimate = aniObj
		}

		if (animateTypes1.includes(type)) {
			if (!stepAnimate.styles.transform) {
				stepAnimate.styles.transform = ''
			}
			let unit = ''
			if (type === 'rotate') {
				unit = 'deg'
			}
			stepAnimate.styles.transform += `${type}(${args.map((v: number) => v + unit).join(',')}) `
		} else {
			stepAnimate.styles[type] = `${args.join(',')}`
		}
		this.currentStepAnimates[this.next] = stepAnimate
	}
	animateRun(styles: Styles = {}, config:StepConfig = {}, ref: any) {
		const el = ref || this.ref
		if (!el) return
		return new Promise((resolve) => {
			const time = +new Date()
			nvueAnimation.transition(el, {
				styles,
				...config
			}, () => {
				resolve(+new Date() - time)
			})
		})
	}
	nextAnimate(animates: StepAnimates, step: number = 0, ref: any, cb: Callback) {
		let obj = animates[step]
		if (obj) {
			let { styles, config } = obj
			// this.duration += config.duration
			this.animateRun(styles, config, ref).then((time: number) => {
				step += 1
				this.duration += time
				this.nextAnimate(animates, step, ref, cb)
			})
		} else {
			this.currentStepAnimates = {}
			cb && cb(this.duration)
		}
	}
	step(config:StepConfig = {}) {
		this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
		this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
		this.next++
		return this
	}
	export(ref: any, cb?: Callback) {
		ref = ref || this.ref
		if(!ref) return
		this.duration = 0
		this.next = 0
		this.nextAnimate(this.currentStepAnimates, 0, ref, cb)
		return null
	}
}


animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
	LimeAnimation.prototype[type] = function(...args: (string | number)[]) {
		this.addAnimate(type, args)
		return this
	}
})
// #endif
export function createAnimation(options : CreateAnimationOptions) {
	// #ifndef APP-NVUE
	return uni.createAnimation({ ...options })
	// #endif
	// #ifdef APP-NVUE
	return new LimeAnimation(options)
	// #endif
}
