import {
	BLUE,
	WHITE
} from '../common/color';
import {
	VantComponent
} from '../common/component';
import {
	getSystemInfoSync
} from '../common/utils';
import {
	isObj
} from '../common/validator';
import {
	canIUseCanvas2d
} from '../common/version';
import {
	adaptor
} from './canvas';

function format(rate) {
	return Math.min(Math.max(rate, 0), 100);
}
const PERIMETER = 2 * Math.PI;
const BEGIN_ANGLE = -Math.PI / 2;
const STEP = 1;
VantComponent({
	props: {
		text: String,
		lineCap: {
			type: String,
			value: 'round',
		},
		value: {
			type: Number,
			value: 0,
			observer: 'reRender',
		},
		speed: {
			type: Number,
			value: 50,
		},
		size: {
			type: Number,
			value: 100,
			observer() {
				this.drawCircle(this.currentValue);
			},
		},
		fill: String,
		layerColor: {
			type: String,
			value: WHITE,
		},
		color: {
			type: null,
			value: BLUE,
			observer() {
				this.setHoverColor().then(() => {
					this.drawCircle(this.currentValue);
				});
			},
		},
		type: {
			type: String,
			value: '',
		},
		strokeWidth: {
			type: Number,
			value: 4,
		},
		clockwise: {
			type: Boolean,
			value: true,
		},
		canvasId: {
			type: String,
			value: ''
		}
	},
	data: {
		hoverColor: BLUE,
	},
	methods: {
		getContext() {
			const {
				type,
				size
			} = this.data;
			if (type === '' || !canIUseCanvas2d()) {
				const ctx = wx.createCanvasContext('van-circle', this);
				return Promise.resolve(ctx);
			}
			const dpr = getSystemInfoSync().pixelRatio;
			return new Promise((resolve) => {
				wx.createSelectorQuery()
					.in(this)
					.select('#van-circle')
					.node()
					.exec((res) => {
						const canvas = res[0].node;
						const ctx = canvas.getContext(type);
						if (!this.inited) {
							this.inited = true;
							canvas.width = size * dpr;
							canvas.height = size * dpr;
							ctx.scale(dpr, dpr);
						}
						resolve(adaptor(ctx));
					});
			});
		},
		setHoverColor() {
			const {
				color,
				size
			} = this.data;
			if (isObj(color)) {
				return this.getContext().then((context) => {
					if (!context)
						return;
					const LinearColor = context.createLinearGradient(size, 0, 0, 0);
					Object.keys(color)
						.sort((a, b) => parseFloat(a) - parseFloat(b))
						.map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key]));
					this.hoverColor = LinearColor;
				});
			}
			this.hoverColor = color;
			return Promise.resolve();
		},
		presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) {
			const {
				strokeWidth,
				lineCap,
				clockwise,
				size
			} = this.data;
			const position = size / 2;
			const radius = position - strokeWidth / 2;
			context.setStrokeStyle(strokeStyle);
			context.setLineWidth(strokeWidth);
			context.setLineCap(lineCap);
			context.beginPath();
			context.arc(position, position, radius, beginAngle, endAngle, !clockwise);
			context.stroke();
			if (fill) {
				context.setFillStyle(fill);
				context.fill();
			}
		},
		renderLayerCircle(context) {
			const {
				layerColor,
				fill
			} = this.data;
			this.presetCanvas(context, layerColor, 0, PERIMETER, fill);
		},
		renderHoverCircle(context, formatValue) {
			const {
				clockwise
			} = this.data;
			// 结束角度
			const progress = PERIMETER * (formatValue / 100);
			const endAngle = clockwise ?
				BEGIN_ANGLE + progress :
				3 * Math.PI - (BEGIN_ANGLE + progress);
			this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle);
		},
		drawCircle(currentValue) {
			const {
				size
			} = this.data;
			this.getContext().then((context) => {
				if (!context)
					return;
				context.clearRect(0, 0, size, size);
				this.renderLayerCircle(context);
				const formatValue = format(currentValue);
				if (formatValue !== 0) {
					this.renderHoverCircle(context, formatValue);
				}
				context.draw();
			});
		},
		reRender() {
			// tofector 动画暂时没有想到好的解决方案
			const {
				value,
				speed
			} = this.data;
			if (speed <= 0 || speed > 1000) {
				this.drawCircle(value);
				return;
			}
			this.clearMockInterval();
			this.currentValue = this.currentValue || 0;
			const run = () => {
				this.interval = setTimeout(() => {
					if (this.currentValue !== value) {
						if (Math.abs(this.currentValue - value) < STEP) {
							this.currentValue = value;
						} else if (this.currentValue < value) {
							this.currentValue += STEP;
						} else {
							this.currentValue -= STEP;
						}
						this.drawCircle(this.currentValue);
						run();
					} else {
						this.clearMockInterval();
					}
				}, 1000 / speed);
			};
			run();
		},
		clearMockInterval() {
			if (this.interval) {
				clearTimeout(this.interval);
				this.interval = null;
			}
		},
	},
	mounted() {
		this.currentValue = this.data.value;
		this.setHoverColor().then(() => {
			this.drawCircle(this.currentValue);
		});
	},
	destroyed() {
		this.clearMockInterval();
	},
});