
interface String {
	decodeAtoB: string;
	encodeBtoA: string;
}

interface Number {
	/**
	 * 检测数字是否在指定范围内，a、b无所谓顺序，随便传就完了，但好歹得是个数字，哪怕是NaN
	 * @param a
	 * @param b
	 * @returns 返回是否在范围内
	 */
	inRange(a: number, b: number): boolean;
}

interface Array<T> {
	/** 操作数组的最后一个元素 */
	lastElement: T;
	/** 异步遍历 */
	forWait<C extends (el: T, index: number, arr: T[])=>Promise<any>>(call: C): Promise<any>;
}

interface ReadonlyArray<T> {
	/** 操作数组的最后一个元素 */
	lastElement: T;
	/** 异步遍历 */
	forWait<C extends (el: T, index: number, arr: T[])=>Promise<any>>(call: C): Promise<any>;
}

declare namespace mtec {
	type type_string = 'string'|'number'|'bigint'|'boolean'|'symbol'|'undefined'|'null'|'object'|'array'|'function';

	type Type<str extends type_string> = str extends type_string ? str extends 'string' ? string : str extends 'number' ? number : str extends 'bigint' ? bigint : str extends 'boolean' ? boolean : str extends 'symbol' ? symbol : str extends 'undefined' ? undefined : str extends 'null' ? null : str extends 'object' ? object : str extends 'array' ? any[] : ((...args: any[])=>any) : str;

	type TypeArray<list extends type_string[]> = list extends [infer start extends type_string, ...infer residue extends type_string[]] ? [mtec.Type<start>, ...(residue['length'] extends 0 ? [] : TypeArray<residue> )] : any;

	type PickFirst<list extends [unknown, ...any][]> = list extends [[infer first, ...any], ...infer residue extends [unknown, ...any][]] ? [first, ...(residue['length'] extends 0 ? [] : PickFirst<residue>)] : any;

	type Fusion<A, B> = A extends object ? A extends Array<infer el_a> ? Array<el_a | (B extends Array<infer el_b> ? el_b : B)> : A extends Function ? A : B extends object ? B extends Function ? A : {[key in (keyof A | keyof B)]: key extends keyof B ? B[key] : key extends keyof A ? A[key] : unknown} : A : A extends boolean|null|undefined|number ? B extends boolean|null|undefined|number ? number : B extends bigint ? bigint : string : A extends bigint ? B extends string|symbol ? string : bigint : string;

	type FusionAll<A, list> = list extends [infer first, ...infer residue] ? residue['length'] extends 0 ? Fusion<A, first> : Fusion<A, FusionAll<first, residue>> : Fusion<A, list>;

	type OmitKeys<O, T> = {[prop in keyof O]: O[prop] extends T ? never : prop}[keyof O];

	/**
	 * 获取一个值的类型
	 * @param value
	 */
	export function vtype(value: any): type_string;

	/**
	 * 比较两个值在数据上是否一致
	 * @param a
	 * @param b
	 * @param record 比较记录，主要是为了避免递归的数据结构，可能导致死循环
	 */
	export function same(a: any, b: any, record?: {cache: string[], mark: Map<any, string>, list: string[]}): boolean;

	export function pickValueByType<T extends [type_string, any][]>(values: any[], types: [...T]): TypeArray<PickFirst<T>>;

	/**
	 * 延迟返回
	 * @param delay - 延迟时间，单位：s
	 * @param call - 回调函数
	 * @param args - 回调参数
	 */
	export function delay<A extends unknown[], C extends (...args: A)=>unknown>(delay: number, call: C, ...args: [...A]): Promise<ReturnType<C>>
	/**
	 * @param delay - 延迟时间，单位：s
	 * @param result - 延迟返回
	 */
	export function delay<R>(delay: number, result: R): Promise<R>;

	/**
	 * 抽签函数
	 * @description 按照权重抽取数据
	 * @param bucket - 签筒数据([数据, 权重][])
	 */
	export function drawLots<B extends [unknown, number][]>(bucket: B): B extends [infer D, number][] ? D : string;

	/**
	 * 合并数据，相同标记的数据，会被最后的数据覆盖
	 * @param target 目标位置
	 * @param data 更新数据
	 */
	export function fusionData<T, list extends (T extends object ? (object&Partial<T>) : any)[]>(target: T, ...args: [...list]): FusionAll<T, list>;

	/**
	 * 克隆数据，并生成新的引用
	 * @param data
	 * @param record 克隆记录，主要是为了避免递归的数据结构，可能导致死循环
	 */
	export function cloneData<D>(data: D, record?: Map<any, any>): D;

	export class CountAverage {
		constructor(init?: number)
		public get average(): number;
		public add(value: number): number;
		public clean(): void;
	}

	/** 裸露的promise */
	export class NudityPromise<V> {
		public promise: Promise<V>;
		/**
		 * 回复promise
		 * @param value
		 */
		public resolve(value: V|PromiseLike<V>): void;
		/**
		 * 拒绝promise
		 * @param reason
		 */
		public reject(reason: any): void;
	}

	export function JsonString(data: any, record?: {mark: Map<any, string>, cache: string[]}): string;
	export function parseJson(json_string: string, record?: {data: Map<string, any>, ref: Map<string, {obj: any, key: string|number|symbol}[]>}): any;
}

declare namespace mtec.string {
	/**
	 * 获取一个指定长度，指定进制的随机数字字符串
	 * @param len - 字符串长度
	 * @param radix - 生成随机字符串的进制
	 */
	export function random(len: number, radix?: number): string;

	/**
	 * 获取一个随机token字符串
	 * @param len - token的长度
	 * @param radix - token使用的进制
	 * @param verify - 用于验证token的有效性
	 */
	export function randomToken(len: number, radix?: number, verify?: (token: string)=>boolean): string;

	/**
	 * 获取一组字符串中的公共词缀
	 * @param list
	 */
	export function getAffix(list: string[]): {prefix: string, suffix: string, max_length: number};

	export function normalLen(value: any, len: number): string;

	/**
	 * 判断字符串数组中是否存在指定的字符串，或者找出一个与指定字符串相似度最高的字符串
	 * @param list
	 * @param str
	 */
	export function findLikeStr(str: string, list: string[]): string;

	/**
	 * 计算两个字符床的相似度
	 * @param a
	 * @param b
	 */
	export function levenshtein(a: string, b: string): number;
}

declare namespace mtec.number {
	/** 圆周率 */
	export var PI: number;
	/** 角度转弧度（转换因子） */
	export var RAD: number;
	/** 弧度转角度（转换因子） */
	export var DEG: number;

	/**
	 * 判断数字是否在[a, b]之间
	 * @param num
	 * @param a
	 * @param b
	 */
	export function inRange(num: number, a: number, b: number): boolean;

	/**
	 * 获取数字num的精度(小数位数)
	 * @param num
	 */
	export function getPrecision(num: number): number;

	/**
	 * 生成一个[a, b]之间的随机数
	 * @param a
	 * @param b
	 * @param precision - 随机数的精度(小数点的位数)
	 */
	export function random(a: number, b: number, precision?: number): number;

	/**
	 * 对于丢失精度导致的循环数，尝试进行还原
	 * @param num
	 */
	export function repair(num: number): number;

	/**
	 * 转换成数字
	 * @param value
	 * @param spare - 备用值
	 */
	export function parse(value: any, spare?: number): number;

	/**
	 * 保留指定位数的小数
	 * @param num 原始数字
	 * @param place 要保留的小数位数
	 * @param floor 是否向下取整，true向下取整，false向上取整，其他情况四舍五入
	 */
	export function fixedNum(num: number, place: number, floor?: boolean): number;

	/**
	 * 将数字限制在[a, b]的区间内
	 * @param num
	 * @param a
	 * @param b
	 */
	export function limit(num: number, a: number, b: number): number;
}

declare namespace mtec.array {
	/**
	 * 随机返回数组中的一个元素
	 * @param arr
	 */
	export function random<A extends any[]>(arr: A): A[number];

	/**
	 * 从数组中返回指定个数的元素
	 * @param arr
	 * @param len
	 * @param repetition 是否可以重复取出同一个元素，默认为false，只当没有明确其值，且[len]大于[arr.length]时，为true
	 */
	export function randomeElement<A extends any[]>(arr: A, len?: number, repetition?: boolean): A;

	/**
	 * 返回数组中的最后一个元素
	 * @param arr
	 * @param index - 倒数第几个元素，默认等于1
	 */
	export function last<A extends any[]>(arr: A, index?: number): A[number];

	/**
	 * 清空数组元素并返回
	 * @param arr
	 */
	export function clear<A extends Array<any>>(arr: A): A;

	/**
	 * 从数组中删除一个指定的元素
	 * @param element
	 * @param head
	 */
	export function remove<A extends Array<any>, el extends A extends Array<infer _> ? _ : any>(arr: A, element: el, head?: boolean): el;
	export function remove<A extends Array<any>, el extends A extends Array<infer _> ? _ : any>(arr: A, verify: (element: el, i: number, arr: A)=>boolean, head?: boolean): el;

	/**
	 * 创建一个指定长度的数组
	 * @param size 数组的长度
	 * @param call 创建元素的回调
	 */
	export function create<el>(size: number, call: (index: number)=>el): el[];
}

declare namespace mtec.color {
	/** 常用颜色映射 */
	var common: {[name: string]: string};

	/**
	 * 根据字符串，获取对应的十六进制颜色值
	 * @param color 表示颜色名称或者十六进制值的字符串
	 */
	export function toHexColor(color: string): string;

	/**
	 * 格式化颜色格式
	 * @param color 表示颜色名称或者十六进制值的字符串
	 */
	export function normalizeHexColor(color: string): string;

	/**
	 * 尝试将字符串转换成rgb颜色
	 * @param color 表示颜色名称或者十六进制值的字符串
	 * @returns [r, g, b]
	 */
	export function toRGBColor(color: string): [number, number, number];

	/**
	 * 尝试将字符串转换成hsl格式颜色
	 * @param color 表示颜色名称或者十六进制值的字符串
	 * @returns [h, s, l]
	 */
	export function toHSLColor(color: string): [number, number, number];

	/**
	 * 把rgb颜色转换成hex字符串
	 * @param r - 红
	 * @param g - 绿
	 * @param b - 蓝
	 */
	export function RGB2Hex(r: number, g: number, b: number): string;

	/**
	 * 把hsl颜色转换成hex字符串
	 * @param h - 色相
	 * @param s - 饱和度
	 * @param l - 明度(亮度)
	 */
	export function HSL2Hex(h: number, s: number, l: number): string;

	/**
	 * 打印名称中包含[cut]片段的颜色
	 * @param cut - 名称片段
	 */
 	export function logColorLike(cut: string): void;

	/**
	 * 打印一条全色谱的线条
	 * @param size - 线条尺寸
	 */
	export function logFullColorLine(size?: number): void;
}

declare namespace mtec.log {
	/**
	 * 标签化输出，并会像console.warn, console.error那样带有堆栈的调用信息\
	 * 如果第一个参数是字符串，会尝试对其进行标签格式化\
	 * 如果符合格式，会在输出时带上标签样式\
	 * 否则则什么都不会发生，该函数的行为表现的和console.log一样
	 * @param tag - 标签字符串 Formate like this 'tag1: color1; tag2: color2; ......tagN: colorN;'
	 * @param args - 其余要输出的参数，行为和正常的log参数一致
	 * @example ```javascript
	 * abi.log.tag('标签1: white', ...args);
	 * abi.log.tag('tag-2: #fff', ...args);
	 * abi.log.tag('tag(标签)3: purple; [标签-tag4]: #808080', ...args);
	 * ```
	 */
	export function tag(tag: string, ...args: any[]): void;

	export function warn(...args: any[]): void;
}

declare namespace mtec.local {
	export function read<D>(key: string, out?: Partial<D>): D;
	export function save(key: string, data: any): void;
}

declare namespace mtec.time {
	/** 一天的时长ms */
	export var ONE_DAY: number;
	/**
	 * 判断两个时间戳是否是同一天
	 * @param d1
	 * @param d2
	 */
	export function sameDay(d1: number, d2: number): boolean;
}

declare namespace mtec.cc {
	type Asset = import('cc').Asset;
	type _types_globals__Constructor<T> = import('cc').__private._types_globals__Constructor<T>;
	type AssetManagerBundle = import('cc').AssetManager.Bundle;
	type Node = import('cc').Node;
	type UITransform = import('cc').UITransform;
	type EventHandler = import('cc').EventHandler;
	type SpriteFrame = import('cc').SpriteFrame;
	type Size = import('cc').Size;
	type Canvas = import('cc').Canvas;
	type Vec2 = import('cc').Vec2;
	type Vec3 = import('cc').Vec3;
	type Vec4 = import('cc').Vec4;

	export const canvas: Canvas;

	/** 游戏的初始化时间(单位：ms) */
	export const initTime: number;
	/** 当前帧的开始时间(单位：ms) */
	export const frameStartTime: number;
	/** 游戏运行的总时长(单位：ms) */
	export const totalTime: number;
	/** 每一帧的期望时长(单位：ms) */
	export const frameTime: number;
	/** 当前帧的剩余时长(单位：ms) */
	export const residueTime: number;

	/**
	 * 创建一个按钮时间句柄
	 * @param options
	 */
	export function creatEventHandle(options: Partial<EventHandler>): EventHandler;

	/**
	 * 加载bundle
	 * @param bundle_name
	 */
	export function loadBundle(bundle_name: string): Promise<AssetManagerBundle>;

	/**
	 * 加载资源
	 * @param path
	 * @param type
	 * @param call
	 */
	export function loadRes<T extends Asset>(path: string, type: _types_globals__Constructor<T>, bundle?: AssetManagerBundle, call?: (asset: T)=>void): void;

	/**
	 * 异步加载资源
	 * @param path
	 * @param type
	 */
	export function loadResAsync<T extends Asset>(path: string, type: _types_globals__Constructor<T>, bundle?: AssetManagerBundle): Promise<T>;

	/** 坐标辅助类 */
	export class VecAssist {
		/**
		 * @param node - 需要坐标辅助的节点
		 * @param ref - 参考节点
		 */
		constructor(node: Node, ref?: Node);

		/** 节点置顶时的y坐标 */
		public top: number;
		/** 节点置底时的y坐标 */
		public bottom: number;
		/** 节点贴靠左侧时的x坐标 */
		public left: number;
		/** 节点贴靠右侧时的x坐标 */
		public right: number;
		/** 节点的下边缘与参考节点的上边缘重合时的y坐标 */
		public over_top: number;
		/** 节点的上边缘与参考节点的下边缘重合时的y坐标 */
		public over_bottom: number;
		/** 节点的右边缘与参考节点的左边缘重合时的x坐标 */
		public over_left: number;
		/** 节点的左边缘与参考节点的右边缘重合时的x坐标 */
		public over_right: number;
		/** 节点相对于参考节点居中时的坐标 */
		public center: Vec3;

		/** 可供操作的vec记录 */
		public readonly vec: Vec3;

		/**
		 * 获取指定对齐情况时的坐标
		 * @description 调用该函数的同时，也会更新实例上的vec缓存
		 * @param x 水平的对齐方式
		 * @param y 垂直的对齐方式
		 */
		public getPosition(x: 'center'|`${''|'over_'}${'left'|'right'|'bottom'|'top'}`, y?:'center'|`${''|'over_'}${'top'|'bottom'}`): Vec3;

		public static getPosition<Dx extends 'center'|`${''|'over_'}${'left'|'right'|'bottom'|'top'}`, Dy extends 'center'|`${''|'over_'}${'top'|'bottom'}`>(node: Node, ref?: Node|Dx, x?: Dx|Dy, y?: Dy): Vec3;
	}

	/**
	 * 为节点更换精灵贴图
	 * @param node
	 * @param sframe
	 * @param inner
	 */
	export function skinPeeler(node: Node, sframe: SpriteFrame, inner?: boolean | {width?: boolean, height?: boolean}): void;

	export function getWorldPosition(node: Node, out?: Vec3): Vec3;
	export function getLocalPosition(local: Node, node: Node, out?: Vec3): Vec3;
	export function getLocalPosition(local: Node, world_position: Vec3, out?: Vec3): Vec3;
	export const is_long_screen: boolean;

	/**
	 * 帧循环\
	 * 只有当，当前帧还有剩余时间时，才会执行回调
	 * @param list 要遍历的数据
	 * @param call 每次遍历要执行的回调函数
	 */
	export function frameWhile<T extends any[]>(list: T, call: (value: T[number], index: number, arr: T)=>void): Promise<0>;

	/**
	 * 在帧空闲的时候，执行回调函数
	 * @param call
	 */
	export function IdleCallback<Param extends any[], R>(call: (...args: [...Param])=>R, args: Param, complete?: (result: R, args: Param)=>void, options?: {start_stamp?: number, timeout?: number}): void;

	/**
	 * 创建一个二维向量
	 * @param x
	 * @param y
	 */
	export function v2(x: number|Vec2|Vec3|Vec4, y?: number): Vec2;
	/**
	 * 创建一个三维向量
	 * @param x
	 * @param y
	 * @param z
	 */
	export function v3(x: number|Vec2|Vec3|Vec4, y?: number, z?: number): Vec3;
	/**
	 * 创建一个四维向量
	 * @param x
	 * @param y
	 * @param z
	 * @param w
	 */
	export function v4(x: number|Vec2|Vec3|Vec4, y?: number, z?: number, w?: number): Vec4;

	/**
	 * 把一个节点（node）以指定的节点（container）为参考，进行适配（使得container内切于node，即node能够铺满container的所有空间，但有可能会超出）
	 * @param node
	 * @param contianer
	 * @description 主要用于适配背景节点
	 */
	export function adaptBackgroundNode(node: Node, contianer?: Node): void;
}

declare namespace mtec.size {

	/**
	 * 获取一个size（target）相对于另一个size（container）的内切尺寸
	 * @param target
	 * @param container
	 */
	export function innerRatio(target: cc.Size, container: cc.Size): number;

	/**
	 * 获取一个size（target）相对于另一size（filler）的外切比例
	 * @param target
	 * @param filler
	 */
	export function exterRatio(target: cc.Size, filler: cc.Size): number;

	/** 设计尺寸 */
	export const designSize: cc.Size;
	/** 当前的画布尺寸 */
	export const canvasSize: cc.Size;
}

declare namespace mtec.vector {
	/**
	 * 计算两个向量的向量差的长度
	 * @param a
	 * @param b
	 */
	export function distance(a: cc.Vec2|cc.Vec3|cc.Vec4, b: cc.Vec2|cc.Vec3|cc.Vec4): number;
}

declare namespace mtec.data {
	/**
	 * 代理拦截数据的 get 回调函数类型
	 * @template T - 数据类型
	 * @template prop - 属性类型
	 * @param {T} proxy - 数据代理对象
	 * @param {T[prop]} value - 属性值
	 * @returns {T[prop]} 属性值
	 */
	type _get_callback_<T, prop extends keyof T> = (proxy: T, value: T[prop])=>T[prop];

	/**
	 * 代理拦截数据的 set 回调函数类型
	 * @template T - 数据类型
	 * @template prop - 属性类型
	 * @param {T} proxy - 数据代理对象
	 * @param {T[prop]} old - 旧属性值
	 * @param {T[prop]} value - 新属性值
	 * @returns {T[prop]} 属性值
	 */
	type _set_callback_<T, prop extends keyof T> = (proxy: T, old: T[prop], value: T[prop])=>T[prop];

	/**
	 * 代理拦截数据
	 * @template T - 数据类型
	 * @typedef {Object} DataBlocker
	 * @property {Object.<keyof T, _get_callback_<T, keyof T>> & {ignore?: Array<OmitKeys<T, Function>>}} get - get 回调
	 * @property {Object.<keyof T, _set_callback_<T, keyof T>> & {ignore?: Array<OmitKeys<T, Function>>}} set - set 回调
	 * @property {(prop: string | symbol, old: any, value: any, hdl: PxiHandle<T>) => void} [afterSet] - set 后回调
	 */
	export type DataBlocker<T> = {
		get?: {[prop in keyof T]?: _get_callback_<T, prop>}&{ignore?: Array<mtec.OmitKeys<T, Function>>},
		set?: {[prop in keyof T]?: _set_callback_<T, prop>}&{ignore?: Array<mtec.OmitKeys<T, Function>>},
		//afterSet?: (prop: string|symbol, old: any, value: any, hdl: PxiHandle<T>)=>void;
	}
}