import EventMng from "../../manager/EventMng";
import LevelRender from "../compment/LevelRender";
import { AutowiredItem } from "./Autowire";
import { BtnEvent } from "./mvc/FguiViewCtrl";

export enum VirtualListType {
	/**
	 * 实列表
	 */
	Real = 1,
	/**
	 * 虚拟列表（非循环
	 */
	Virtual = 2,
	/**
	 * 虚拟循环列表
	 */
	VirtualAndLoop = 3,
}

export class ListUtil {
	// static readonly TweenInTime = 0.19;
	static readonly TweenInTime = 0.5;
	static readonly TweenDelayTime = 0.11;

	dataList: any[];
	gList: fgui.GList;
	param: any;

	private needTween: number;
	private aniName: string;
	private delay: number = ListUtil.TweenDelayTime;

	/**
	 * 列表管理类（需要注意同一个fgui资源不应该被不同的类重复拓展）
	 * @param glist 管理的列表
	 * @param uiClass 拓展的列表资源类(自己定义一个类，继承Itemrender类)
	 * @param listType 列表类型，见ListType 1.(默认开启虚拟列表，如果要开启虚拟列表，必须设置滚动 2.(虚拟循环列表不支持横向或纵向流动
	 * @param levelrender 开启分层渲染，（内容物包含遮罩的禁止使用!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!）
	 */
	constructor(glist: fgui.GList, uiClass: (new () => ItemRender) | (new () => ItemLabelRender) = null, listType: VirtualListType = VirtualListType.Virtual, levelrender: boolean = false) {
		this.gList = glist;
		if (levelrender) glist._container.addComponent(LevelRender);
		if (uiClass) {
			let item = glist.getFromPool();
			if (!item) {
				if (CC_PREVIEW) console.error("列表内没有添加默认资源");
				return;
			}
			if (item.packageItem.extensionType && item.packageItem.extensionType != uiClass) {
				if (CC_PREVIEW) console.warn(`列表${this.gList.name}内的默认资源资源${item.resourceURL}, 已经被`, item.packageItem.extensionType, "拓展");
				return;
			}
			item.packageItem.extensionType = uiClass;
			fgui.UIObjectFactory.extensions[item.resourceURL] = uiClass;
		}
		switch (listType) {
			case VirtualListType.Virtual:
				this.gList.setVirtual();
				break;
			case VirtualListType.VirtualAndLoop:
				this.gList.setVirtualAndLoop();
				break;
		}
	}

	/**
	 * 列表内容可变时需要自己预先根据url预先拓展（fgui.UIObjectFactory.setExtension
	 * @param cb 提供item的url回调
	 * @param target 绑定
	 */
	setItemProvider(cb: (index: number) => string, target: any = this) {
		this.gList.itemProvider = cb.bind(target);
	}

	/**
	 * 刷新列表
	 * @param list 数据
	 * @param param 额外参数
	 */
	refreshItems(list: any[], param?: any) {
		this.dataList = list;
		this.param = param;
		this.gList.itemRenderer = this.refreshItem.bind(this);
		this.gList.numItems = list.length;
		this.gList.ensureBoundsCorrect();
		this.clearTween();
	}

	private refreshItem(index: number, render: ItemRender) {
		let data = this.dataList[index];
		try {
			render.__refreshData(data, index, this.param, this.needTween, this.aniName, this.delay);
		} catch (err) {
			if (CC_PREVIEW) console.warn(err);
		}
	}

	setTween(line: number, aniName: string = null, delay: number = ListUtil.TweenDelayTime) {
		this.needTween = line;
		this.aniName = aniName;
		this.delay = delay;
	}

	clearTween() {
		this.needTween = 0;
		this.aniName = null;
		this.delay = ListUtil.TweenDelayTime;
	}
}

export abstract class ItemRender extends fairygui.GButton implements AutowiredItem {
	__autowired: string[];
	private __tween__: cc.Tween;
	index: number;
	__AutoGetItem() {
		this.__autowired?.forEach((key: string) => {
			this[key] = this.getChild(key);
		});
	}

	__refreshData(data: any, index: number, param: any, needTween: number, aniName: string = null, delay: number = ListUtil.TweenDelayTime) {
		if (needTween) this.__ShowTween(index, needTween, aniName, delay);
		else this.__clearTween();
		this.index = index;
		this.setData(data, index, param);
	}

	/**
	 * @param data 列表数据
	 * @param index 列表内资源对应下标，从0开始
	 * @param param 额外参数
	 */
	abstract setData(data: any, index?: number, param?: any);

	/**通知事件列表 */
	private _notifyEventList: Map<string, Function> = new Map<string, Function>();
	//计时器ID列表
	private m_Timers: Set<number> = new Set();
	/** 按钮点击注册器 */
	private btnClicks: BtnEvent[] = [];

	protected onConstruct(): void {
		this.__AutoGetItem();
		this.onInit();
	}

	protected onEnable(): void {
		this.onShow();
	}

	protected onDisable(): void {
		this.offEvent();
		this.RemoveAllClick();
		this.RemoveTimers();
		this.__clearTween();
		this.onHide();
	}

	onShow() { }

	onHide() { }

	onInit() { }

	/**
	 * 获取所有控制器并赋值
	 */
	initControllers() {
		for (let i of this.controllers) {
			this[i.name] = i;
		}
	}

	offEvent() {
		try {
			let self = this;
			this._notifyEventList.forEach((f, key) => {
				EventMng.off(key, f, self);
			}, this);
			this._notifyEventList.clear();
		} catch (error) {
			if (CC_PREVIEW) console.error("onDisable->" + error);
		}
	}
	/**注册notice事件，disable的时候会自动移除 */
	initEvent(eventName: string, cb: Function) {
		if (this._notifyEventList.get(eventName) != null) return;
		this._notifyEventList.set(eventName, cb);
		EventMng.on(eventName, cb, this);
	}

	/**
	 * 增加定时器
	 * @param callback
	 * @param delta 单位毫秒ms
	 */
	AddTimer(callback: Function, delta: number) {
		let timer = setInterval(() => {
			callback.apply(this);
		}, delta);
		this.m_Timers.add(timer);
	}

	/** 移除所有定时器 */
	RemoveTimers() {
		this.m_Timers.forEach((element) => {
			clearInterval(element);
		});
		this.m_Timers.clear();
	}

	/**
	 * 一次性定时器
	 * @param callback
	 * @param delta 单位毫秒ms
	 */
	AddTimerOnce(callback: Function, delta: number) {
		let timer = setInterval(() => {
			clearInterval(timer);
			this.m_Timers.delete(timer);
			callback();
		}, delta);
		this.m_Timers.add(timer);
		return timer;
	}

	RegisterClick(btn: fairygui.GObject, func: Function) {
		btn.onClick(func, this);
		this.btnClicks.push({ btn: btn, func: func });
	}

	RemoveAllClick() {
		this.btnClicks.forEach((element) => {
			element.btn.offClick(element.func, this);
		});
	}

	private __fguiTweentimer = null;
	private __ShowTween(index: number, needTween: number, aniName: string = null, delayTime: number = ListUtil.TweenDelayTime) {
		if (this.__tween__) {
			this.__tween__.stop();
		}
		let delay = Math.floor(index / needTween) * delayTime;
		if (aniName != null) {
			if (this.__fguiTweentimer) clearInterval(this.__fguiTweentimer);
			this.alpha = 0;
			this.__fguiTweentimer = this.AddTimerOnce(() => {
				this.alpha = 1;
				this.getTransition(aniName).play();
				this.__fguiTweentimer = null;
			}, delay * 1000);
		} else {
			this.alpha = 0;
			this.__tween__ = cc
				.tween(this as fairygui.GObject)
				.delay(delay)
				.to(ListUtil.TweenInTime, {
					alpha: 1,
				})
				.call(() => {
					this.alpha = 1;
				})
				.start();
		}
	}
	private __clearTween() {
		this.__tween__?.stop();
		this.alpha = 1;
	}
}

export abstract class ItemLabelRender extends fairygui.GLabel implements AutowiredItem {
	__autowired: string[];
	private __tween__: cc.Tween;

	__AutoGetItem() {
		this.__autowired?.forEach((key: string) => {
			this[key] = this.getChild(key);
		});
	}

	__refreshData(data: any, index: number, param: any, needTween: number, aniName: string = null, delay: number = ListUtil.TweenDelayTime) {
		if (needTween > 0) this.__ShowTween(index, needTween, aniName, delay);
		else this.__clearTween();
		this.setData(data, index, param);
	}

	/**
	 * @param data 列表数据
	 * @param index 列表内资源对应下标，从0开始
	 * @param param 额外参数
	 */
	abstract setData(data: any, index?: number, param?: any);

	/**通知事件列表 */
	private _notifyEventList: Map<string, Function> = new Map<string, Function>();
	//计时器ID列表
	private m_Timers: Set<number> = new Set();
	/** 按钮点击注册器 */
	private btnClicks: BtnEvent[] = [];

	protected onConstruct(): void {
		this.__AutoGetItem();
		this.onInit();
	}

	protected onEnable(): void {
		this.onShow();
	}

	protected onDisable(): void {
		this.offEvent();
		this.RemoveAllClick();
		this.RemoveTimers();
		this.__clearTween();
		this.onHide();
	}

	onShow() { }

	onHide() { }

	onInit() { }

	/**
	 * 获取所有控制器并赋值
	 */
	initControllers() {
		for (let i of this.controllers) {
			this[i.name] = i;
		}
	}

	offEvent() {
		try {
			let self = this;
			this._notifyEventList.forEach((f, key) => {
				EventMng.off(key, f, self);
			}, this);
			this._notifyEventList.clear();
		} catch (error) {
			if (CC_PREVIEW) console.error("onDisable->" + error);
		}
	}
	/**注册notice事件，disable的时候会自动移除 */
	initEvent(eventName: string, cb: Function) {
		if (this._notifyEventList.get(eventName) != null) return;
		this._notifyEventList.set(eventName, cb);
		EventMng.on(eventName, cb, this);
	}

	/**
	 * 增加定时器
	 * @param callback
	 * @param delta 单位毫秒ms
	 */
	AddTimer(callback: Function, delta: number) {
		let timer = setInterval(() => {
			callback.apply(this);
		}, delta);
		this.m_Timers.add(timer);
	}

	/** 移除所有定时器 */
	RemoveTimers() {
		this.m_Timers.forEach((element) => {
			clearInterval(element);
		});
		this.m_Timers.clear();
	}

	/**
	 * 一次性定时器
	 * @param callback
	 * @param delta 单位毫秒ms
	 */
	AddTimerOnce(callback: Function, delta: number) {
		let timer = setInterval(() => {
			clearInterval(timer);
			this.m_Timers.delete(timer);
			callback();
		}, delta);
		this.m_Timers.add(timer);
		return timer;
	}

	RegisterClick(btn: fairygui.GObject, func: Function) {
		btn.onClick(func, this);
		this.btnClicks.push({ btn: btn, func: func });
	}

	RemoveAllClick() {
		this.btnClicks.forEach((element) => {
			element.btn.offClick(element.func, this);
		});
	}

	private __fguiTweentimer = null;
	private __ShowTween(index: number, needTween: number, aniName: string = null, delayTime: number = ListUtil.TweenDelayTime) {
		if (this.__tween__) {
			this.__tween__.stop();
		}
		let delay = Math.floor(index / needTween) * delayTime;
		if (aniName != null) {
			if (this.__fguiTweentimer) clearInterval(this.__fguiTweentimer);
			this.alpha = 0;
			this.__fguiTweentimer = this.AddTimerOnce(() => {
				this.alpha = 1;
				this.getTransition("aniName")?.play();
				this.__fguiTweentimer = null;
			}, delay * 1000);
		} else {
			this.alpha = 0;
			this.__tween__ = cc
				.tween(this as fairygui.GObject)
				.delay(delay)
				.to(ListUtil.TweenInTime, {
					alpha: 1,
				})
				.call(() => {
					this.alpha = 1;
				})
				.start();
		}
	}

	private __clearTween() {
		this.__tween__?.stop();
		this.__tween__ = null;
		this.alpha = 1;
	}
}
