import { Command } from "./Command";
import { findLayerRecursively } from "../utils/layerHelper";
import { fabric } from "fabric-with-all";
import {
	findObjectById,
	generateId,
	insertObjectAtZIndex,
	removeCanvasObjectByObject,
	createPatternTransform,
} from "../utils/helper";
import { restoreFabricObject } from "../utils/objectHelper";

const scale = 0.3;// 默认缩放比例

export const FillSourceToBase64 = (source) => {
	if (source?.toDataURL) {
		return source.toDataURL?.();
	} else if (source?.src) {
		return source.src;
	}
	return source;
}

/**
 * 填充图案平铺命令
 * 填充重复属性：repeat | repeat-x | repeat-y | no-repeat
 * 默认缩放比例：0.3
 * 默认偏移量：50%
 */
export class FillRepeatCommand extends Command {
	constructor(options) {
		super({ name: "填充图案平铺", saveState: true });
		this.canvas = options.canvas;
		this.layers = options.layers;
		this.canvasManager = options.canvasManager;
		this.layerManager = options.layerManager;
		this.layerId = options.layerId;
		this.fillRepeat = options.fillRepeat;
		this.oldObjects = null;
		this.oldLocked = null;
		this.oldIsDisableUnlock = null;
	}

	async execute() {
		const { layer } = findLayerRecursively(this.layers.value, this.layerId);
		if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
			console.warn("图层不存在或没有 fabric 对象");
			return false;
		}
		const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
		if (!object || (object.type !== "rect" && object.type !== "image")) {
			console.warn("当前对象不能平铺", object.type);
			return false;
		}
		this.oldObjects = object;
		if (this.fillRepeat === "no-repeat") {
			const fill_ = object.fill_;
			const image = await new Promise((resolve, reject) => {
				fabric.Image.fromURL(
					fill_.source,
					v => resolve(v),
					{ crossOrigin: "anonymous" }
				);
			});
			image.set({
				id: object.id,
				layerId: object.layerId,
				layerName: object.layerName,
				...(fill_.originalInfo || {
					top: object.top,
					left: object.left,
				})
			});
			layer.fabricObjects = [image.toObject(["id", "layerId", "layerName"])];
			this.oldLocked = layer.locked;
			layer.locked = false;

			this.canvas.add(image);
			this.canvas.remove(object);
		} else {
			const img = await new Promise((resolve, reject) => {
				if (object.type === "rect") {
					let source = object.fill.source;
					resolve(source);
				} else if (object.type === "image") {
					const imgElement = object.getElement();
					// 创建透明 Canvas
					const tcanvas = document.createElement('canvas');
					tcanvas.width = imgElement.width;
					tcanvas.height = imgElement.height;
					const ctx = tcanvas.getContext('2d');
					ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
					ctx.drawImage(imgElement, 0, 0);
					resolve(tcanvas);
				}
			});
			const fill_ = object.fill_ || {
				source: FillSourceToBase64(img),
				gapX: 0,
				gapY: 0,
				width: img.width,
				height: img.height,
				originalInfo: {
					top: object.top,
					left: object.left,
					scaleX: object.scaleX,
					scaleY: object.scaleY,
					width: object.width,
					height: object.height,
				}
			};
			const bgObject = this.canvasManager.getBackgroundLayerObject();
			const pattern = new fabric.Pattern({
				source: img,
				repeat: this.fillRepeat,
				patternTransform: object.fill?.hasOwnProperty("patternTransform") ? object.fill.patternTransform : createPatternTransform(scale, 0),
				offsetX: object.fill?.hasOwnProperty("offsetX") ? object.fill.offsetX : bgObject.width / 2, // 水平偏移
				offsetY: object.fill?.hasOwnProperty("offsetY") ? object.fill.offsetY : bgObject.height / 2, // 垂直偏移
			});
			const rect = new fabric.Rect({
				id: object.id,
				layerId: object.layerId,
				layerName: object.layerName,
				fill_,
			});
			layer.fabricObjects = [rect.toObject(["id", "layerId", "layerName"])];
			this.oldLocked = layer.locked;
			// this.oldIsDisableUnlock = layer.isDisableUnlock;
			// layer.isDisableUnlock = true;
			if (this.oldObjects.type === "rect") {
				rect.set({
					width: object.width,
					height: object.height,
					top: object.top,
					left: object.left,
					originX: object.originX,
					originY: object.originY,
					angle: object.angle,
					scaleX: object.scaleX,
					scaleY: object.scaleY,
					flipX: object.flipX,
					flipY: object.flipY,
				});
			} else {
				let scaleX = bgObject.scaleX || 1;
				let scaleY = bgObject.scaleY || 1;
				rect.set({
					width: bgObject.width,
					height: bgObject.height,
					top: bgObject.top - bgObject.height * scaleY / 2,
					left: bgObject.left - bgObject.width * scaleX / 2,
					scaleX,
					scaleY,
				});
				layer.locked = true;
			}
			rect.set("fill", pattern);
			this.canvas.add(rect);
			this.canvas.remove(object);
		}
		await this.layerManager?.updateLayersObjectsInteractivity();
		await this.layerManager?.sortLayersWithTool?.();
		await this.canvasManager.thumbnailManager?.generateLayerThumbnail(
			this.layerId
		);
		await this.layerManager.selectLayerObjects(this.layerId);
		return true;
	}

	async undo() {
		if (!this.oldObjects) {
			console.warn("没有旧对象可恢复");
			return false;
		}
		const { layer } = findLayerRecursively(this.layers.value, this.oldObjects.layerId);
		if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
			console.warn("图层不存在或没有 fabric 对象");
			return false;
		}
		const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
		this.canvas.remove(object);
		this.canvas.add(this.oldObjects);
		layer.fabricObjects = [this.oldObjects.toObject(["id", "layerId", "layerName"])];
		layer.locked = this.oldLocked;
		// layer.isDisableUnlock = this.oldIsDisableUnlock;
		await this.layerManager?.updateLayersObjectsInteractivity();
		await this.layerManager?.sortLayersWithTool?.();
		this.canvas.renderAll();
		this.canvasManager.thumbnailManager?.generateLayerThumbnail(this.layerId);
		return true;
	}
}


/**
 * 填充图案更改参数
 */
export class FillRepeatChangeCommand extends Command {
	constructor(options) {
		super({ name: "填充图案更改参数", saveState: true });
		this.canvas = options.canvas;
		this.layers = options.layers;
		this.canvasManager = options.canvasManager;
		this.layerManager = options.layerManager;
		this.layerId = options.layerId;
		this.newPattern = options.newPattern;
		this.oldPattern = null;
	}

	async execute() {
		const { layer } = findLayerRecursively(this.layers.value, this.layerId);
		if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
			console.warn("图层不存在或没有 fabric 对象");
			return false;
		}
		const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
		if (!object || object.type !== "rect") {
			console.warn("当前对象不是矩形", object);
			return false;
		}
		this.oldPattern = object.oldPattern || object.get("fill");
		delete object.oldPattern;
		const oldPattern = { ...this.oldPattern };
		delete oldPattern.id;
		const pattern = new fabric.Pattern({
			...oldPattern,
			...this.newPattern,
		});
		object.set("fill", pattern);
		this.canvas.renderAll();
		return true;
	}

	async undo() {
		if (!this.oldPattern) {
			console.warn("没有旧图案可恢复");
			return false;
		}
		const { layer } = findLayerRecursively(this.layers.value, this.layerId);
		if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
			console.warn("图层不存在或没有 fabric 对象");
			return false;
		}
		const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
		if (!object || object.type !== "rect") {
			console.warn("当前对象不是矩形", object);
			return false;
		}
		const pattern = new fabric.Pattern({
			...this.oldPattern
		});
		object.set("fill", pattern);
		this.canvas.renderAll();
		return true;
	}
}

/**
 * 填充图案更改间隙
 */
export class FillRepeatGapChangeCommand extends Command {
	constructor(options) {
		super({ name: "填充图案更改间隙", saveState: true });
		this.canvas = options.canvas;
		this.layers = options.layers;
		this.canvasManager = options.canvasManager;
		this.layerManager = options.layerManager;
		this.layerId = options.layerId;
		this.newGapX = options.newGapX;
		this.newGapY = options.newGapY;
		this.record = !!options.record;
		this.oldGapX = null;
		this.oldGapY = null;
	}

	async execute(isUndo = false) {
		const { layer } = findLayerRecursively(this.layers.value, this.layerId);
		if (!layer || !layer.fabricObjects || layer.fabricObjects.length === 0) {
			console.warn("图层不存在或没有 fabric 对象");
			return false;
		}
		const { object } = findObjectById(this.canvas, layer?.fabricObjects?.[0]?.id);
		if (!object || object.type !== "rect") {
			console.warn("当前对象不是矩形", object);
			return false;
		}
		if (!object.fill_) {
			object.fill_ = {
				source: FillSourceToBase64(object.fill.source),
				gapX: 0,
				gapY: 0,
			}
		}
		if (isUndo) {
			object.fill_.gapX = this.oldGapX;
			object.fill_.gapY = this.oldGapY;
		} else {
			if (!object.oldFill_ && this.record) {
				object.oldFill_ = { ...object.fill_ };
			}
			this.oldGapX = object.fill_.gapX;
			this.oldGapY = object.fill_.gapY;
			object.fill_.gapX = this.newGapX;
			object.fill_.gapY = this.newGapY;
		}
		const image = new Image();
		image.src = object.fill_.source;
		await image.decode();
		object.fill_.width = image.width;
		object.fill_.height = image.height;
		// 创建透明 Canvas
		const tcanvas = document.createElement('canvas');
		tcanvas.width = image.width + object.fill_.gapX;
		tcanvas.height = image.height + object.fill_.gapY;
		const ctx = tcanvas.getContext('2d');
		ctx.clearRect(0, 0, tcanvas.width, tcanvas.height);
		ctx.drawImage(image, 0, 0);

		const fill = object.get("fill");
		fill.source = tcanvas;
		object.set("fill", new fabric.Pattern(fill));
		this.canvas.renderAll();
		return true;
	}

	async undo() {
		if (this.oldGapX === null || this.oldGapY === null) {
			console.warn("没有旧间隙可恢复");
			return false;
		}
		await this.execute(true);
		return true;
	}

}