import { LSignatureOptions, Point, Line } from '../../index.uts'

let points : Line = []
let undoStack : Line[] = [];
let redoStack : Line[] = [];
let lastX = 0;
let lastY = 0;


export class Signature {
	el : UniElement
	options : LSignatureOptions = {
		penColor: 'black',
		openSmooth: true,
		disableScroll: true,
		disabled: false,
		penSize: 2,
		minLineWidth: 2,
		maxLineWidth: 6,
		minSpeed: 1.5,
		maxWidthDiffRate: 20,
		maxHistoryLength: 20
	} as LSignatureOptions
	ctx : DrawableContext
	isEmpty : boolean = true
	isDrawing : boolean = false
	// historyList : Point[][] = []
	// id : string
	// instance : ComponentPublicInstance
	constructor(el : UniElement) {
		this.el = el
		this.ctx = el.getDrawableContext() as DrawableContext
		this.init()
	}
	init() {
		this.el.addEventListener('touchstart', this.onTouchStart)
		this.el.addEventListener('touchmove', this.onTouchMove)
		this.el.addEventListener('touchend', this.onTouchEnd)
	}
	remove() {
		this.el.removeEventListener('touchstart', this.onTouchStart as UniCallbackWrapper)
		this.el.removeEventListener('touchmove', this.onTouchMove as UniCallbackWrapper)
		this.el.removeEventListener('touchend', this.onTouchEnd as UniCallbackWrapper)
	}
	setOption(options : LSignatureOptions) {
		this.options = options
	}
	disableScroll(event : UniTouchEvent) {
		event.stopPropagation()
		if (this.options.disableScroll) {
			{
				event.preventDefault()
			}
		}
	}
	getTouchPoint(event : UniTouchEvent) : Point {
		const rect = this.el.getBoundingClientRect()
		const touche = event.touches[0];
		const x = touche.clientX
		const y = touche.clientY
		// const force = touche.force
		return {
			x: x - rect.left,
			y: y - rect.top
		} as Point
	}
	onTouchStart: (event : UniTouchEvent) => void = (event : UniTouchEvent) =>{
		if (this.options.disabled) {
			return
		}
		this.disableScroll(event)
		const { x, y } = this.getTouchPoint(event)
		this.isDrawing = true;
		this.isEmpty = false
		lastX = x
		lastY = y
		points.push({ x, y } as Point);
	}
	onTouchMove: (event : UniTouchEvent) => void = (event : UniTouchEvent) =>{
		if (this.options.disabled || !this.isDrawing) {
			return
		}
		this.disableScroll(event)
		const { x, y } = this.getTouchPoint(event)
		const lineWidth = this.options.penSize
		const strokeStyle = this.options.penColor
		const point = { x, y } as Point
		const last = { x: lastX, y: lastY } as Point
		this.drawLine(point, last, lineWidth, strokeStyle)

		lastX = x
		lastY = y
		points.push({ x, y, c: strokeStyle, w: lineWidth } as Point);
	}
	onTouchEnd: (event : UniTouchEvent) => void = (event : UniTouchEvent) =>{
		this.disableScroll(event)
		this.isDrawing = false;
		undoStack.push(points);
		redoStack = [] as Line[];
		points = [] as Point[];
	}
	drawLine(point : Point, last : Point, lineWidth : number, strokeStyle : string) {
		const ctx = this.ctx
		ctx.lineWidth = lineWidth
		ctx.strokeStyle = strokeStyle
		ctx.lineCap = 'round'
		ctx.lineJoin = 'round'
		ctx.beginPath()
		ctx.moveTo(last.x, last.y)
		ctx.lineTo(point.x, point.y)
		ctx.stroke()
		ctx.update()
	}
	// addHistory() { }
	clear() {
		this.ctx.reset()
		this.ctx.update()
		this.isEmpty = true
		undoStack = [] as Line[];
		redoStack = [] as Line[];
		points = [] as Point[];
	}
	undo() {
		if(redoStack.length == this.options.maxHistoryLength && this.options.maxHistoryLength != 0){
			return
		}
		this.ctx.reset()
		if(undoStack.length > 0){
			const lastPath : Line = undoStack.pop()!;
			redoStack.push(lastPath);
			if(undoStack.length == 0){
				this.isEmpty = true
				this.ctx.update()
				return
			}
			for (let l = 0; l < undoStack.length; l++) {
				for (let i = 1; i < undoStack[l].length; i++) {
					const last  = undoStack[l][i - 1]
					const point = undoStack[l][i]
					this.drawLine(point, last, point.w!, point.c!)
				}
			}
		} else {
			this.ctx.update()
		}
	}
	redo() {
		if(redoStack.length < 1) return
		const lastPath : Line = redoStack.pop()!;
		undoStack.push(lastPath);
		this.isEmpty = false
		for (let l = 0; l < undoStack.length; l++) {
			for (let i = 1; i < undoStack[l].length; i++) {
				const last  = undoStack[l][i - 1]
				const point = undoStack[l][i]
				this.drawLine(point, last, point.w!, point.c!)
			}
		}
	}
	// restore() { }
}