import { gameMethod } from "../../common/gameMethod";
import { RedUtilType } from "../../data/const/TypeConst";
import { ItemLabelRender } from "./ListUtil";

export class RedUtil {
	private static _redMap: Map<RedUtilType, RedDotClass> = new Map();

	static clear() {
		this._redMap.clear()
	}

	static registerBaseRed(type: RedUtilType, func: () => boolean, target: any = null) {
		if (this.getRedDot(type)) {
			if (CC_PREVIEW) console.warn("红点" + type + "已经注册过了");
			return;
		}
		let red = new RedDotBase(type, func.bind(target));
		if (red == null) return;
		this._redMap.set(type, red);
	}

	static registerUpperRed(type: RedUtilType, childs: RedUtilType[], func: () => boolean = null) {
		if (this.getRedDot(type)) {
			if (CC_PREVIEW) console.warn("红点" + type + "已经注册过了");
			return;
		}

		let rednode = new RedDotNode(type);
		this.setChilds(rednode, childs);
		this._redMap.set(type, rednode);
	}

	static getRedState(type: RedUtilType): boolean {
		let red = this.getRedDot(type);
		if (red == null) {
			if (CC_PREVIEW) console.warn(`红点 ${type} 不存在`);
			return false;
		}
		return red.getRedState();
	}

	static getRedDot(type) {
		return this._redMap?.get(type);
	}

	static upRedNode(type: RedUtilType, node: RedDot) {
		let red = this.getRedDot(type);
		if (red == null) {
			if (CC_PREVIEW) console.warn(`节点:${node.name} 的红点 ${type} 不存在 `);
			return;
		}
		if (red.node && red.node != node) {
			if (CC_PREVIEW) console.warn(`节点${red.node?.name}已经挂载了${type}红点，${node?.name}重复挂载了`);
			return;
		}
		red.node = node;
	}

	static offRedNode(type: RedUtilType) {
		let red = this.getRedDot(type);
		if (red == null) {
			if (CC_PREVIEW) console.warn(`红点 ${type} 不存在 `);
			return;
		}
		red.node = null;
	}

	private static setChilds(red: RedDotNode, childs: RedUtilType[]) {
		for (let child of childs) {
			if (child == red.type) {
				if (CC_PREVIEW) console.warn(`红点 ${red.type} 不能自己依赖自己`);
				continue;
			}
			this.setChild(red.type, child);
		}
		red.childs = childs;
	}

	static updateRed(type: RedUtilType) {
		let red = this.getRedDot(type);
		if (red instanceof RedDotBase) {
			red.updateRed();
		} else {
			if (CC_PREVIEW) console.warn(`红点类型不是底部红点 ${type}`);
		}
	}

	private static setChild(parent: RedUtilType, child: RedUtilType) {
		let red = this._redMap.get(child);
		//排除重复挂载依赖
		if (red == null) {
			if (CC_PREVIEW) console.warn(`${child} 红点不存在`);
			return
		}
		if (red.parent) {
			if (CC_PREVIEW) console.warn(`${child} 已经有父红点了`);
			return
		}
		red.parent = parent;
	}

	public static initRedUtil() {
		this._redMap?.forEach((red: RedDotClass) => {
			if (red instanceof RedDotBase) red.updateRed();
		});
	}
}

abstract class RedDotClass {
	type: RedUtilType;
	parent: RedUtilType;
	node: RedDot;

	constructor(type: RedUtilType) {
		this.type = type;
	}

	abstract getRedState(): boolean;

	abstract updateRed();
}

class RedDotNode extends RedDotClass {
	childs: RedUtilType[] = [];

	getRedState(): boolean {
		let isred = false;
		for (let i of this.childs) {
			let red = RedUtil.getRedDot(i);
			isred = red.getRedState();
			if (isred) break;
		}
		return isred;
	}

	updateRed() {
		this.node?.upRed();
		if (this.parent) {
			let red = RedUtil.getRedDot(this.parent);
			if (red == null) {
				if (CC_PREVIEW) console.warn(`红点:${this.parent} 不存在`);
				return;
			}
			red.updateRed();
		}
	}
}

class RedDotBase extends RedDotClass {
	redCount: boolean;
	func: () => boolean;

	constructor(type: RedUtilType, func: () => boolean) {
		super(type);
		this.func = func;
	}

	reCalRed(): boolean {
		try {
			this.redCount = this.func() ?? false;
		} catch (err) {
			if (CC_PREVIEW) console.warn(err);
			this.redCount = false;
		}
		return this.redCount;
	}

	getRedState(): boolean {
		return this.redCount;
	}

	updateRed() {
		this.reCalRed();
		this.node?.upRed();
		if (this.parent) {
			let red = RedUtil.getRedDot(this.parent);
			if (red == null) {
				if (CC_PREVIEW) console.warn(`红点:${this.parent} 不存在`);
				return;
			}
			red.updateRed();
		}
	}
}

export class RedDot extends ItemLabelRender {
	type: RedUtilType;
	show: fairygui.Controller;

	onInit(): void {
		this.initControllers();
	}

	onShow(): void {
		this.upNode();
	}

	onHide(): void {
		this.offNode();
	}

	upNode() {
		if (this.type == null) {
			this.show.selectedIndex = 1;
			return;
		}
		RedUtil.upRedNode(this.type, this);
		this.upRed();
	}

	offNode() {
		if (this.type == null) return;
		RedUtil.offRedNode(this.type);
	}

	setData(data: RedUtilType, index?: number, param?: any) {
		this.type = data;
		this.upNode()
	}

	upRed() {
		if (gameMethod.isEmpty(this.node)) {
			return;
		}
		this.show.selectedIndex = RedUtil.getRedState(this.type) ? 0 : 1;
	}

	isShow() {
		return this.show.selectedIndex == 0;
	}
}
