import { fabric } from 'fabric-with-all'
import { OperationType } from '../tools/layerHelper'
import { getObjectAlphaToCanvas, traceImageContour, clipCanvasTransparent, cloneObjects } from '../tools/canvasMethod'
import { getSegAnythingImage } from '@/api/depth-canvas'
import { useGlobalStore, useUserInfoStore } from '@/stores'

/** 智能框选工具管理器 */
export class AISelectboxToolManager {
	// 管理器	
	canvasManager: any
	stateManager: any
	layerManager: any
	toolManager: any

	targetObject: any
	isDragging: boolean = false
	startX: number = 0
	startY: number = 0

	indicatorObject: any// 指示框对象
	demoObject: any// 演示框对象
	tcanvas: any// 临时画布对象

	tools = [
		OperationType.AISELECT_ADD,
		OperationType.AISELECT_REMOVE,
		OperationType.AISELECT_DRAW,
		OperationType.AISELECT_ERASER
	]
	constructor(options) {
		this.canvasManager = options.canvasManager
		this.stateManager = options.stateManager
		this.layerManager = options.layerManager
		this.toolManager = options.toolManager
	}
	/** 处理切换工具 */
	handleToolChange(oldTool: string, newTool: string) {
		const oldIsAAA = this.tools.includes(oldTool)
		const newIsAAA = this.tools.includes(newTool)
		if (!oldIsAAA && newIsAAA) {
			// 普通工具切换到智能框选工具
			this.init()
			this.canvasManager.discardActiveObject()
		} else if (oldIsAAA && !newIsAAA) {
			// 智能框选工具切换到普通工具
			this.clear()
		}
	}
	/** 切换到橡皮擦工具 */
	changeToolToEraser() {
		if (!this.demoObject) return;
		this.demoObject.set({ erasable: true })
	}

	init() {
		console.log("初始化智能框选工具")
		this.clear();
		this.createDemoObject()
		this.tcanvas = null;
		this.targetObject = null;
		this.canvasManager.getObjects().forEach((obj) => {
			if (obj?.info?.isOriginal) {
				this.targetObject = obj.toObject();
			}
		})
		// const image = this.layerManager.getActiveLayer()
		// if (image && image.info.isAiSelect) {
		// 	this.targetObject = image;
		// } else {
		// 	this.targetObject = null;
		// }

	}
	clear() {
		console.log("清除智能框选工具")
		this.clearDemoObject()
		this.clearIndicatorObject()
		this.isDragging = false
		this.canvasManager.canvas.renderAll()
	}
	demoObjectDefault = {
		left: 0,
		top: 0,
		evented: false,
		selectable: false,
		erasable: false,
	}
	createDemoObject() {
		if (this.demoObject) this.clearDemoObject()
		const { canvasWidth, canvasHeight } = this.canvasManager.getCanvasSize();
		const canvas = document.createElement('canvas')
		canvas.width = canvasWidth
		canvas.height = canvasHeight
		this.demoObject = new fabric.Image(canvas, this.demoObjectDefault)
		this.canvasManager.canvas.add(this.demoObject)
		this.canvasManager.canvas.renderAll()
	}
	clearDemoObject() {
		this.canvasManager.canvas.remove(this.demoObject)
		this.demoObject = null
	}
	createIndicatorObject() {
		this.clearIndicatorObject()
		var color = 'rgba(0, 255, 0, 0.5)'
		if (this.toolManager.currentTool.value === OperationType.AISELECT_REMOVE) {
			color = 'rgba(255, 0, 0, 0.5)'
		}
		const rect = new fabric.Rect({
			left: this.startX,
			width: 0,
			height: 0,
			fill: color,
			stroke: '#000',
			strokeWidth: 1,
			evented: false,
		})
		this.indicatorObject = rect
		this.canvasManager.canvas.add(rect)
		this.canvasManager.canvas.renderAll()
	}
	clearIndicatorObject() {
		this.canvasManager.canvas.remove(this.indicatorObject)
		this.indicatorObject = null
	}
	resetDemoObject() {
		this.clearDemoObject()
		this.createDemoObject()
	}
	// 创建临时画布对象
	async createStaticCanvas(object: fabric.Object) {
		if (!this.demoObject) this.createDemoObject()
		const canvas = new fabric.StaticCanvas(document.createElement("canvas"), {
			width: this.demoObject.width,
			height: this.demoObject.height,
			enableRetinaScaling: false,
		});
		const newObject = await cloneObjects([object]).then(v => v[0])
		canvas.add(newObject)
		canvas.renderAll()
		return canvas
	}
	// 处理绘制图像
	async handleDrawImage(object: fabric.Object) {
		if (!this.targetObject) return;
		const tcanvas = await this.createStaticCanvas(this.demoObject)
		tcanvas.add(object)
		tcanvas.renderAll();
		const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, this.rgba);
		this.replaceDemoObject(canvas)
	}
	// 处理图像删除
	async handleRemoveImage(object: fabric.Object) {
		if (!this.targetObject) return;
		const tcanvas = await this.createStaticCanvas(this.demoObject)
		const rcanvas = await this.createStaticCanvas(object)
		const tempCanvas = rcanvas.toCanvasElement();
		const tempCtx = tempCanvas.getContext('2d');
		const imageData2 = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
		const canvas = getObjectAlphaToCanvas(tcanvas, imageData2, 0, this.rgba);
		this.replaceDemoObject(canvas)
	}
	// 替换框选对象
	async replaceDemoObject(canvas) {
		const image = new fabric.Image(canvas, this.demoObjectDefault);
		this.canvasManager.canvas.add(image)
		this.canvasManager.canvas.remove(this.demoObject);
		this.demoObject = image;
		this.canvasManager.canvas.renderAll()
	}

	mouseDownEvent(e) {
		if (!this.targetObject) return;
		const tool = this.toolManager.currentTool.value
		const tools = [OperationType.AISELECT_ADD, OperationType.AISELECT_REMOVE]
		if (!tools.includes(tool)) return;

		this.isDragging = true
		this.startX = e.absolutePointer.x
		this.startY = e.absolutePointer.y
		this.createIndicatorObject()
	}
	mouseMoveEvent(e) {
		if (!this.targetObject) return;
		if (!this.isDragging) return;
		let width = e.absolutePointer.x - this.startX
		let height = e.absolutePointer.y - this.startY
		let left = this.startX
		let top = this.startY
		if (width < 0) {
			left += width
			width = -width
		}
		if (height < 0) {
			top += height
			height = -height
		}
		this.indicatorObject.set({ width, height, left, top })
		this.canvasManager.canvas.renderAll()
	}
	async mouseUpEvent(e) {
		if (!this.targetObject) return;
		if (!this.isDragging) return;
		this.isDragging = false;
		const object = this.indicatorObject.toJSON("evented")
		if (object.width === 0 || object.height === 0) return

		this.clearIndicatorObject()
		this.canvasManager.canvas.renderAll()

		useGlobalStore().setLoading(true)
		const x1 = Math.round(object.left)
		const y1 = Math.round(object.top)
		const x2 = Math.round(object.left + object.width)
		const y2 = Math.round(object.top + object.height)
		const data = {
			type: "box",
			box: [x1, y1, x2, y2],
		}
		const url = await this.getSegAnythingImage(data)
		const image = await this.loadImageToObject(url)
		// const rect = new fabric.Rect({
		// 	left: object.left,
		// 	top: object.top,
		// 	width: object.width,
		// 	height: object.height,
		// 	fill: '#f00',
		// 	strokeWidth: 0,
		// })
		const currentTool = this.toolManager.currentTool.value
		if (currentTool === OperationType.AISELECT_ADD) {
			await this.handleDrawImage(image)
		} else if (currentTool === OperationType.AISELECT_REMOVE) {
			await this.handleRemoveImage(image)
		}
		useGlobalStore().setLoading(false)
	}


	loadImageToObject(url) {
		return new Promise((resolve, reject) => {
			fabric.Image.fromURL(url, (img) => {
				resolve(img);
			}, { crossOrigin: "anonymous" });// 防止污染
		});
	}
	rgba = { r: 255, g: 0, b: 0, a: 127.5 };
	selectionStyle = {
		stroke: "rgba(255, 77, 71, 1)",
		strokeWidth: 1.5,
		strokeDashArray: [4, 4],
		fill: "transparent",
		strokeUniform: true, // 保持描边宽度不随缩放改变
		selectable: false,
		evented: false,
		absolutePositioned: true,
	};
	async createSelectbox() {
		if (!this.targetObject) return;
		if (!this.demoObject) return
		const fobject = this.demoObject
		this.clearDemoObject()
		const scaleY = fobject.scaleY
		const scaleX = fobject.scaleX
		const top = fobject.top
		const left = fobject.left
		let minX = fobject.width;
		let minY = fobject.height;
		const tcanvas = await this.createStaticCanvas(fobject)
		const canvas = getObjectAlphaToCanvas(tcanvas, null, 0, { r: 255, g: 255, b: 255, a: 255 });

		/** 路径裁剪法 */
		// const arr = traceImageContour(canvas);
		// const str = arr.map((v) => {
		// 	if (v.x < minX) minX = v.x;
		// 	if (v.y < minY) minY = v.y;
		// 	return `${v.x} ${v.y}`
		// }).join(" L ");
		// const path = new fabric.Path(`M ${str} z`);
		// path.set({
		// 	left: left + minX,
		// 	top: top + minY,
		// 	scaleX: scaleX,
		// 	scaleY: scaleY,
		// 	...this.selectionStyle,
		// });

		/** 图片裁剪法 */
		const info = clipCanvasTransparent(canvas)
		minX = info.minX
		minY = info.minY
		const path = new fabric.Image(info.canvas)
		path.set({
			left: left + minX,
			top: top + minY,
			scaleX: scaleX,
			scaleY: scaleY,
			absolutePositioned: true,
		})


		// 创建分组层
		const group = await this.layerManager.createGroupLayer({
			clipPath: path,
			top: path.top + path.height / 2,
			left: path.left + path.width / 2,
		}, false, false)
		const rect = await this.layerManager.createRectLayer({
			width: path.width,
			height: path.height,
			left: left + minX,
			top: top + minY,
			fill: "rgba(255, 186, 186, 0.5)",
			info: { parentId: group.info.id },
		}, false, true)
		await this.canvasManager.updateSubLayerClipPath()
		await this.layerManager.updateLayerThumbnailsById(rect.info.id, "", false)
		await this.layerManager.updateLayerThumbnailsById(group.info.id, rect.thumbnail)
		this.stateManager.recordState()
		this.toolManager.setTool(OperationType.SELECT)
	}

	/** 获取分隔后图片 */
	async getSegAnythingImage(obj) {
		return new Promise((resolve, reject) => {
			if (!this.targetObject) return;
			const user_id = useUserInfoStore().state.userInfo.id;
			const image_path = this.targetObject.src;
			const data = {
				image_path,
				user_id,
				...obj,
			}
			getSegAnythingImage(data).then((res) => {
				console.log(res)
				resolve(res)
			}).catch((error) => {
				console.error(error);
				useGlobalStore().setLoading(false)
			})
		});
	}

	dispose() {
		this.clear()
	}
}
