import { DateFormat, LunarType, DiffUnit, FromToOptions, DatetimeOptions, IsBetweenContains, DatetimeUnit, IKuxDayjs } from "../utssdk/interface.uts";
import { Lunar } from './calendar';
import { DateType, DateUtil } from './date';
import { MONTHS, WEEKDAYS, MONTH_DAYS } from './constant';
import { floor } from './utils';

class KuxDayjs implements IKuxDayjs {
	public d : Date
	public dd : DateType
	private lunar : Lunar
	private dateUtil : DateUtil
	private dateStr : string
	private uniVersion : number

	constructor(date : string = '', isTimestamp : boolean = false, isCST : boolean = true) {
		this.uniVersion = uni.getSystemInfoSync().uniCompileVersionCode;
		this.dateStr = date;
		this.lunar = new Lunar();
		this.dateUtil = new DateUtil();
		const dd = this.dateUtil.getDate(date);
		this.dd = dd;
		this.d = new Date(dd.year, dd.month - 1, dd.date, dd.hour, dd.minute, dd.second, dd.millisecond);
		// if (this.uniVersion >= 4.0) {
		// 	this.d = new Date(date);
		// }
		if (isTimestamp) {
			let timestamp = parseInt(date);
			if (isCST) {
				timestamp += 8 * 3600 * 1000;
			}
			this.fromTimestamp(timestamp);
		}
	}

	/**
	 * 根据时间戳实例化
	 * @param {number} timestamp 时间戳
	 */
	private fromTimestamp(timestamp : number) : KuxDayjs {
		const dd = this.dateUtil.parseTimestamp(timestamp);
		this.dd = this.dateUtil.getDate(`${`${dd.year}`.padStart(2, '0')}-${`${dd.month}`.padStart(2, '0')}-${`${dd.day}`.padStart(2, '0')} ${`${dd.hours}`.padStart(2, '0')}:${`${dd.minutes}`.padStart(2, '0')}:${`${dd.seconds}`.padStart(2, '0')}.${`${dd.milliseconds}`.padStart(3, '0')}`);
		this.d = new Date(dd.year, dd.month - 1, dd.day, dd.hours, dd.minutes, dd.seconds, dd.milliseconds);

		return this;
	}

	/**
	 * 当前时间对象
	 * @description 返回一个基于指定日期和时间的 KuxDayjs 对象
	 * @param {string} date 日期时间字符串，比如：'2023-12-12 19:35:35'
	 */
	dayjs(date : string) : IKuxDayjs {
		this.dateStr = date;
		this.lunar = new Lunar();
		this.dateUtil = new DateUtil();
		const dd = this.dateUtil.getDate(date);
		this.dd = dd;
		// this.d = new Date(dd.year, dd.month - 1, dd.date, dd.hour, dd.minute, dd.second, dd.millisecond);
		if (this.uniVersion >= 4.0) {
			this.d = new Date(date);
		}

		return this;
	}

	/**
	 * 基于当前时间复制一个 KuxDayjs 对象
	 * @returns {KuxDayjs}
	 * @example
	 * const a = dayjs();
	 * const b = a.clone();
	 * // a 和 b 是两个独立的 KuxDayjs 对象
	 */
	clone() : IKuxDayjs {
		return new KuxDayjs();
	}

	/**
	 * 日期格式化
	 * @description 根据传入的占位符返回格式化后的日期
	 * @param format 格式，如 'YYYY-MM-DD HH:mm:ss'
	 * @returns string
	 */
	format(format : string) : string {
		const YYYY = `${this.d.getFullYear()}`;
		const YY = YYYY.slice(-2);
		const M = `${this.d.getMonth() + 1}`;
		const MM = M.padStart(2, '0');
		const DD = `${this.d.getDate()}`.padStart(2, '0');
		const HH = `${this.d.getHours()}`.padStart(2, '0');
		const mm = `${this.d.getMinutes()}`.padStart(2, '0');
		const ss = `${this.d.getSeconds()}`.padStart(2, '0');
		const SSS = `${this.d.getMilliseconds()}`.padStart(3, '0');

		// 上午/下午
		let ampm = 'AM';
		let ampmCN = '上午';
		let ampmZN = 'am';
		let formattedHours = HH;
		if (Math.abs(parseInt(HH)) >= 12 && (format.includes('A') || format.includes('a') || format.includes('AA'))) {
			ampm = 'PM';
			ampmCN = '下午';
			ampmZN = 'pm';
			formattedHours = `${(Math.abs(parseInt(HH)) - 12)}`.padStart(2, '0');
		}

		return format
			.replace('YYYY', YYYY)
			.replace('YY', YY)
			.replace('MM', MM)
			.replace('DD', DD)
			.replace('HH', formattedHours)
			.replace('mm', mm)
			.replace('ss', ss)
			.replace('SSS', SSS)
			.replace('AA', ampmCN)
			.replace('A', ampm)
			.replace('a', ampmZN)
	}
	
	private _diffCommon(dd: DateType, time1: number, time2: number, unit: DiffUnit, strict: boolean): number {
		// 计算两个日期的毫秒数差
		const diffInMilliseconds = Math.abs(time1 - time2);
		// 秒数差
		const diffSeconds = diffInMilliseconds / 1000;
		// 分钟差
		const diffMinutes = diffSeconds / 60;
		// 小时差
		const diffHours = diffMinutes / 60;
		// 天数差
		const diffDays = diffHours / 24;
		// 周数差
		// const diffWeeks = diffDays / 7;
		const week1 = Math.ceil((new Date(dd.year, dd.month, dd.date).getDate() - 1) / 7);
		const week2 = Math.ceil((this.d.getDate() - 1) / 7);
		const diffWeeks = Math.abs(week1 - week2);
		// 月数差
		const year1 = dd.year;
		const year2 = this.d.getFullYear();
		const month1 = dd.month;
		const month2 = this.d.getMonth() + 1;
		
		const diffMonths = (year1 - year2) * 12 + (month1 - month2);
		
		// 年数差
		const diffYear = year1 - year2;
		
		// 判断单位
		let data : number;
		
		switch (unit) {
			case 'millisecond':
				data = diffInMilliseconds;
				break;
			case 'ms':
				data = diffInMilliseconds;
				break;
			case 'second':
				data = diffSeconds;
				break;
			case 's':
				data = diffSeconds;
				break;
			case 'minute':
				data = diffMinutes;
				break;
			case 'M':
				data = diffMinutes;
				break;
			case 'hour':
				data = diffHours;
				break;
			case 'h':
				data = diffHours;
				break;
			case 'week':
				data = diffWeeks;
				break;
			case 'w':
				data = diffWeeks;
				break;
			case 'month':
				data = diffMonths;
				break;
			case 'm':
				data = diffMonths;
				break;
			case 'y':
				data = diffYear;
				break;
			case 'year':
				data = diffYear;
				break;
			default:
				data = diffDays;
				break;
		}
		
		if (!strict) {
			// data = Math.floor(data);
			data = floor(data);
		}
		
		return Math.abs(data);
	}
	
	private _diffByDate(date: IKuxDayjs, unit: DiffUnit, strict: boolean): number {
		const time1 = this.d.getTime();
		const time2 = date.d.getTime();
		
		return this._diffCommon(date.dd, time1, time2, unit, strict);
	}

	private _diff(date : string, unit : DiffUnit, strict : boolean) : number {
		// 将日期转换为毫秒数
		const time1 = this.d.getTime();
		const dd = this.dateUtil.getDate(date);
		const time2 = new Date(dd.year, dd.month - 1, dd.date, dd.hour, dd.minute, dd.second, dd.millisecond).getTime();

		return this._diffCommon(dd, time1, time2, unit, strict);
	}
	
	diff(date : IKuxDayjs) : number

	diff(date : string) : number
	
	diff(date : IKuxDayjs, unit : DiffUnit | null) : number

	diff(date : string, unit : DiffUnit | null) : number
	
	diff(date : IKuxDayjs, unit : DiffUnit | null, strict : boolean | null): number

	diff(date : string, unit : DiffUnit | null, strict : boolean | null) : number
	
	// #ifndef APP-HARMONY
	diff(date : any, unit : DiffUnit | null, strict : boolean | null) : number {
		// #ifdef APP-ANDROID
		if (date instanceof IKuxDayjs) {
			return this._diffByDate(date as IKuxDayjs, unit ?? 'ms', strict ?? false);
		}
		// #endif
		// #ifndef APP-ANDROID
		if (date instanceof KuxDayjs) {
			return this._diffByDate(date as IKuxDayjs, unit ?? 'ms', strict ?? false);
		}
		// #endif
		
		return this._diff(`${date}`, unit ?? 'ms', strict ?? false);
	}
	// #endif
	// #ifdef APP-HARMONY
	diff(date : any, unit ?: DiffUnit | null, strict ?: boolean | null) : number {
		// #ifdef APP-ANDROID
		if (date instanceof IKuxDayjs) {
			return this._diffByDate(date as IKuxDayjs, unit ?? 'ms', strict ?? false);
		}
		// #endif
		// #ifndef APP-ANDROID
		if (date instanceof KuxDayjs) {
			return this._diffByDate(date as IKuxDayjs, unit ?? 'ms', strict ?? false);
		}
		// #endif
		
		return this._diff(`${date}`, unit ?? 'ms', strict ?? false);
	}
	// #endif

	private _calendar(year : number, month : number) : DateFormat[] {
		let outDate : DateFormat[] = [];
		let date = new Date();
		let curYear = year;
		let curMonth = month;

		if (isNaN(curYear) || curYear < 1900) {
			curYear = date.getFullYear();
		}

		if (isNaN(curMonth) || curMonth < 1) {
			curMonth = date.getMonth() + 1;
		}

		// 获取当月第一天
		const firstDayOfThisMonth = new Date(curYear, curMonth - 1, 1);
		const preMonthDay = firstDayOfThisMonth.getDay();
		// 获取上月的最后一天，即本月第0天
		const lastDayOfPreMonth = new Date(curYear, curMonth - 1, 0);
		const lastDateOfLastMonth = lastDayOfPreMonth.getDate();
		// 获取本月最后一天，即下月第0天
		const lastDayOfThisMonth = new Date(curYear, curMonth, 0);
		const lastDateOfThisMonth = lastDayOfThisMonth.getDate();

		// 获取周日期数据，一个月最多跨6周，即6 * 7格式排版
		for (let i = 0; i < 6 * 7; i++) {
			// 获取当前排序日期
			let thisYear : number = curYear,
				thisMonth : number = curMonth,
				dateN : number = i + 1 - preMonthDay,
				cursorDate : number = dateN;

			if (dateN <= 0) {
				thisMonth -= 1;
				cursorDate = dateN + lastDateOfLastMonth;
			} else if (dateN > lastDateOfThisMonth) {
				// date大于本月最后一天为下月预留天数
				thisMonth += 1;
				cursorDate = dateN - lastDateOfThisMonth;
			}

			if (thisMonth == 13) {
				thisMonth = 1;
				thisYear += 1;
			}
			if (thisMonth == 0) {
				thisMonth = 12;
				thisYear -= 1;
			}

			// 计算该日期与当前时间的天数差
			// const diffInDays = this.diff()
			const startDate = new Date(thisYear, thisMonth - 1, cursorDate);
			const endDate = new Date(this.d.getFullYear(), this.d.getMonth(), this.d.getDate());
			const fullDate = `${thisYear}-${`${thisMonth}`.padStart(2, '0')}-${`${cursorDate}`.padStart(2, '0')}`;

			let diffInDays = this.diff(fullDate);
			// let diffInDays = 0;

			if (startDate.getTime() < endDate.getTime()) {
				diffInDays *= -1;
			}

			outDate.push({
				year: thisYear,
				month: thisMonth,
				date: cursorDate,
				isToday: this.dateUtil.getlunar(thisYear, thisMonth, cursorDate).isToday,
				diffDays: diffInDays,
				render: {},
				lunar: {
					month: this.lunar.toChinaMonth(this.lunar.solar_date(thisYear, thisMonth, cursorDate).lunarM),
					date: this.lunar.toChinaDay(this.lunar.solar_date(thisYear, thisMonth, cursorDate).lunarD)
				} as LunarType,
				fullLunar: this.lunar.solar_date(thisYear, thisMonth, cursorDate),
				fullDate
			} as DateFormat)
		}

		return outDate;
	}

	calendar() : DateFormat[]

	calendar(year : number | null) : DateFormat[]

	// #ifndef APP-HARMONY
	calendar(year : number | null, month : number | null) : DateFormat[] {
		return this._calendar(year ?? 0, month ?? 0);
	}
	// #endif
	// #ifdef APP-HARMONY
	calendar(year ?: number | null, month ?: number | null) : DateFormat[] {
		return this._calendar(year ?? 0, month ?? 0);
	}
	// #endif

	private _millsecond(ms : number) : number {
		if (ms > -1) {
			return this.d.getTime();
		}

		return this.d.setMilliseconds(ms);
	}

	millisecond() : number

	// #ifndef APP-HARMONY
	millisecond(ms : number | null) : number {
		return this._millsecond(ms ?? -1);
	}
	// #endif
	// #ifdef APP-HARMONY
	millisecond(ms ?: number | null) : number {
		return this._millsecond(ms ?? -1);
	}
	// #endif

	private _second(s : number) : number {
		if (s > -1) {
			return this.d.setSeconds(s);
		}

		return this.d.getSeconds();
	}

	second() : number

	// #ifndef APP-HARMONY
	second(s : number | null) : number {
		return this._second(s ?? -1);
	}
	// #endif
	// #ifdef APP-HARMONY
	second(s ?: number | null) : number {
		return this._second(s ?? -1);
	}
	// #endif

	private _minute(M : number) : number {
		if (M > -1) {
			return this.d.setMinutes(M);
		}

		return this.d.getMinutes();
	}

	minute() : number

	// #ifndef APP-HARMONY
	minute(M : number | null) : number {
		return this._minute(M ?? -1);
	}
	// #endif
	// #ifdef APP-HARMONY
	minute(M ?: number | null) : number {
		return this._minute(M ?? -1);
	}
	// #endif

	private _hour(h : number) : number {
		if (h > -1) {
			return this.d.setHours(h);
		}

		return this.d.getHours();
	}

	hour() : number

	// #ifndef APP-HARMONY
	hour(h : number | null) : number {
		return this._hour(h ?? -1);
	}
	// #endif
	// #ifdef APP-HARMONY
	hour(h ?: number | null) : number {
		return this._hour(h ?? -1);
	}
	// #endif

	private _date(d : number | null) : number {
		if (d != null) {
			return this.d.setDate(d);
		}

		return this.d.getDate();
	}

	date() : number

	// #ifndef APP-HARMONY
	date(d : number | null) : number {
		return this._date(d);
	}
	// #endif
	// #ifdef APP-HARMONY
	date(d ?: number | null) : number {
		return this._date(d);
	}
	// #endif

	/**
	 * 获取星期几，0 表示星期天。目前仅支持获取，不支持设置操作
	 * @description 获取或设置星期
	 * @returns {number} 返回0-6的整数，0代表星期日，1代表星期一，以此类推。
	 */
	day() : number {
		return this.d.getDay();
	}

	/**
	 * 获取/设置时间
	 * @description 获取或设置毫秒
	 * @param {number} t 一个整数，表示从 1970-1-1 00:00:00 UTC 开始计时的毫秒数。 传入参数就是设置操作，否则为获取操作。
	 * @returns {number} 返回UTC 1970 年 1 月 1 日 00:00:00 与更新日期之间的毫秒数（实际上是自变量的值）。
	 */
	time(t : number) : number {
		if (!isNaN(parseInt(`${t}`))) {
			return this.d.setTime(parseInt(`${t}`));
		}

		return this.d.getTime();
	}

	private _month(m : number) : number {
		if (m > -1) {
			return this.d.setMonth(m);
		}

		return this.d.getMonth();
	}

	month() : number

	// #ifndef APP-HARMONY
	month(m : number | null) : number {
		return this._month(m ?? -1);
	}
	// #endif
	// #ifdef APP-HARMONY
	month(m ?: number | null) : number {
		return this._month(m ?? -1);
	}
	// #endif

	private _year(y : number) : number {
		if (y > 1969) {
			return this.d.setFullYear(y);
		}

		return this.d.getFullYear();
	}

	year() : number

	// #ifndef APP-HARMONY
	year(y : number | null) : number {
		return this._year(y ?? 1969);
	}
	// #endif
	// #ifdef APP-HARMONY
	year(y ?: number | null) : number {
		return this._year(y ?? 1969);
	}
	// #endif

	private _add(count : number, unit : DiffUnit) : IKuxDayjs {
		if (count < 0) {
			console.warn('【kux-dayjs:add】请输入大于0的数字');
			return this;
		}
		if (unit == 'day' || unit == 'd') {
			this.d.setDate(this.d.getDate() + count);
		} else if (unit == 'month' || unit == 'M') {
			this.d.setMonth(this.d.getMonth() + count);
		} else if (unit == 'year' || unit == 'y') {
			this.d.setFullYear(this.d.getFullYear() + count);
		} else if (unit == 'week' || unit == 'w') {
			this.d.setDate((this.d.getDate() + 7) * count);
		} else if (unit == 'hour' || unit == 'h') {
			this.d.setHours(this.d.getHours() + count);
		} else if (unit == 'minute' || unit == 'm') {
			this.d.setMinutes(this.d.getMinutes() + count);
		} else if (unit == 'second' || unit == 's') {
			this.d.setSeconds(this.d.getSeconds() + count);
		} else if (unit == 'millisecond' || unit == 'ms') {
			this.d.setMilliseconds(this.d.getMilliseconds() + count);
		}

		return this;
	}

	add() : IKuxDayjs

	add(count : number | null) : IKuxDayjs

	// #ifndef APP-HARMONY
	add(count : number | null, unit : DiffUnit | null) : IKuxDayjs {
		return this._add(count ?? 0, unit ?? 'day');
	}
	// #endif
	// #ifdef APP-HARMONY
	add(count ?: number | null, unit ?: DiffUnit | null) : IKuxDayjs {
		return this._add(count ?? 0, unit ?? 'day');
	}
	// #endif

	private _subtract(count : number, unit : DiffUnit) : IKuxDayjs {
		if (count < 0) {
			console.warn('【kux-dayjs:subtract】请输入大于0的数字');
			return this;
		}
		if (unit == 'day' || unit == 'd') {
			this.d.setDate(this.d.getDate() - count);
		} else if (unit == 'month' || unit == 'M') {
			this.d.setMonth(this.d.getMonth() - count);
		} else if (unit == 'year' || unit == 'y') {
			this.d.setFullYear(this.d.getFullYear() - count);
		} else if (unit == 'week' || unit == 'w') {
			this.d.setDate((this.d.getDate() - 7) * count);
		} else if (unit == 'hour' || unit == 'h') {
			this.d.setHours(this.d.getHours() - count);
		} else if (unit == 'minute' || unit == 'm') {
			this.d.setMinutes(this.d.getMinutes() - count);
		} else if (unit == 'second' || unit == 's') {
			this.d.setSeconds(this.d.getSeconds() - count);
		} else if (unit == 'millisecond' || unit == 'ms') {
			this.d.setMilliseconds(this.d.getMilliseconds() - count);
		}

		return this;
	}

	subtract() : IKuxDayjs

	subtract(count : number | null) : IKuxDayjs

	/**
	 * 减去
	 * @description 返回减去一定时间的复制的 KuxDayjs 对象
	 * @param {string} count 需要减去的整数，支持配合单位操作
	 * @param {DiffUnit} unit 单位，默认为 `day`
	 * + week 周，缩写 `w`
	 * + day 天，缩写 `d`
	 * + month 月份，缩写 `M`
	 * + year 年，缩写 `y`
	 * + hour 小时，缩写 `h`
	 * + minute 分钟，缩写 `m`
	 * + second 秒，缩写 `s`
	 * + millisecond 毫秒，缩写 `ms`
	 * @returns {Date} d 操作后的Date对象
	 */
	// #ifndef APP-HARMONY
	subtract(count : number | null, unit : DiffUnit | null) : IKuxDayjs {
		return this._subtract(count ?? 0, unit ?? 'day');
	}
	// #endif
	// #ifdef APP-HARMONY
	subtract(count ?: number | null, unit ?: DiffUnit | null) : IKuxDayjs {
		return this._subtract(count ?? 0, unit ?? 'day');
	}
	// #endif

	/**
	 * 设置时间为0时0分0秒0毫秒
	 */
	private _setTimeStart() : IKuxDayjs {
		this.d.setHours(0);
		this.d.setMinutes(0);
		this.d.setSeconds(0);
		this.d.setMilliseconds(0);

		return this;
	}

	/**
	 * 设置时间为23时59分59秒999毫秒
	 */
	private _setTimeEnd() {
		this.d.setHours(23);
		this.d.setMinutes(59);
		this.d.setSeconds(59);
		this.d.setMilliseconds(999);
	}

	/**
	 * 设置时间为今天
	 */
	today() : IKuxDayjs {
		this.d = new Date();

		return this;
	}

	/**
	 * 时间的开始
	 * @description 返回复制的 KuxDayjs 对象，并设置到一个时间的开始。
	 * @param {DiffUnit} unit 单位
	 * + week 周，缩写 `w`
	 * + day 天，缩写 `d`
	 * + month 月份，缩写 `M`
	 * + year 年，缩写 `y`
	 * + hour 小时，缩写 `h`
	 * + minute 分钟，缩写 `m`
	 * + second 秒，缩写 `s`
	 * @returns {Date} d 操作后的Date对象
	 */
	startOf(unit : DiffUnit) : IKuxDayjs {
		// this.today();

		if (unit == 'week' || unit == 'w') {
			const day = this.d.getDay();
			this.d.setDate((this.d.getDate() - day + (day == 0 ? -6 : 1)));
			this._setTimeStart();
		} else if (unit == 'day' || unit == 'd') {
			this._setTimeStart();
		} else if (unit == 'month' || unit == 'M') {
			this.d.setDate(1);
			this._setTimeStart();
		} else if (unit == 'year' || unit == 'y') {
			this.d.setMonth(0);
			this.d.setDate(1);
			this._setTimeStart();
		} else if (unit == 'hour' || unit == 'h') {
			this.d.setMinutes(0);
			this.d.setSeconds(0);
			this.d.setMilliseconds(0);
		} else if (unit == 'minute' || unit == 'm') {
			this.d.setSeconds(0);
			this.d.setMilliseconds(0);
		} else if (unit == 'second' || unit == 's') {
			this.d.setMilliseconds(0);
		}

		return this;
	}

	/**
	 * 时间的结束
	 * @description 返回复制的 KuxDayjs 对象，并设置到一个时间的末尾。
	 * @param {DiffUnit} unit 单位
	 * + week 周，缩写 `w`
	 * + day 天，缩写 `d`
	 * + month 月份，缩写 `M`
	 * + year 年，缩写 `y`
	 * + hour 小时，缩写 `h`
	 * + minute 分钟，缩写 `m`
	 * + second 秒，缩写 `s`
	 * @returns {Date} d 操作后的Date对象
	 */
	endOf(unit : DiffUnit) : IKuxDayjs {
		// this.today();

		if (unit == 'week' || unit == 'w') {
			const day = this.d.getDay();
			this.d.setDate(this.d.getDate() + (7 - day));
			this._setTimeEnd();
		} else if (unit == 'day' || unit == 'd') {
			this._setTimeEnd();
		} else if (unit == 'month' || unit == 'M') {
			const year = this.d.getFullYear();
			const month = this.d.getMonth() + 1;
			this.d = new Date(year, month, 0);
			this._setTimeEnd();
		} else if (unit == 'year' || unit == 'y') {
			const year = this.d.getFullYear();
			this.d = new Date(year, 11, 31);
			this._setTimeEnd();
		} else if (unit == 'hour' || unit == 'h') {
			this.d.setMinutes(59);
			this.d.setSeconds(59);
			this.d.setMilliseconds(999);
		} else if (unit == 'minute' || unit == 'm') {
			this.d.setSeconds(59);
			this.d.setMilliseconds(999);
		} else if (unit == 'second' || unit == 's') {
			this.d.setMilliseconds(999);
		}

		return this;
	};

	private _fromOrto(date : Date, options : FromToOptions = {
		isSuffix: false,
		relativeTime: {
			s: '',
			m: '',
			mm: '',
			h: '',
			hh: '',
			d: '',
			dd: '',
			mon: '',
			mons: '',
			y: '',
			yy: ''
		}
	} as FromToOptions, type : 'from' | 'to' = 'from') : string {
		const now = date.getTime();
		let diff = now - this.d.getTime();
		const diffSeconds = Math.floor(diff / 1000);
		const diffMinutes = Math.floor(diffSeconds / 60);
		const diffHours = Math.floor(diffMinutes / 60);
		const diffDays = Math.floor(diffHours / 24);
		const diffMonths = Math.floor(diffDays / 30.44);
		const diffYears = Math.floor(diffMonths / 12);

		const isSuffix = options.isSuffix ?? false;
		const s = options.relativeTime?.s ?? '';
		const m = options.relativeTime?.m ?? '';
		const mm = options.relativeTime?.mm ?? '';
		const h = options.relativeTime?.h ?? '';
		const hh = options.relativeTime?.hh ?? '';
		const d = options.relativeTime?.d ?? '';
		const dd = options.relativeTime?.dd ?? '';
		const mon = options.relativeTime?.mon ?? '';
		const mons = options.relativeTime?.mons ?? '';
		const y = options.relativeTime?.y ?? '';
		const yy = options.relativeTime?.yy ?? '';

		let outStr = '';
		let suffix = isSuffix ? '' : (type == 'from' ? '前' : '后');

		if (diffSeconds > 0 && diffSeconds < 45) {
			outStr = `${diffSeconds}秒${suffix}`;
			if (s.includes('%s')) {
				outStr = s;
				outStr = outStr.replace('%s', `${diffSeconds}`);
			}
		} else if (diffSeconds >= 45 && diffSeconds <= 89) {
			outStr = `1分钟${suffix}`;
			if (m.includes('%m')) {
				outStr = m;
				outStr = outStr.replace('%m', `1`);
			}
		} else if (diffSeconds >= 90 && diffMinutes <= 44) {
			outStr = `${diffMinutes}分钟${suffix}`;
			if (mm.includes('%mm')) {
				outStr = mm;
				outStr = outStr.replace('%mm', `${diffMinutes}`);
			}
		} else if (diffMinutes >= 45 && diffMinutes <= 89) {
			outStr = `1小时${suffix}`;
			if (h.includes('%h')) {
				outStr = h;
				outStr = outStr.replace('%h', '1');
			}
		} else if (diffMinutes >= 90 && diffHours <= 21) {
			outStr = `${diffHours}小时${suffix}`;
			if (hh.includes('%hh')) {
				outStr = hh;
				outStr = outStr.replace('%hh', `${diffHours}`);
			}
		} else if (diffHours >= 22 && diffHours <= 35) {
			outStr = `1天${suffix}`;
			if (d.includes('%d')) {
				outStr = d;
				outStr = outStr.replace('%d', `1`);
			}
		} else if (diffHours >= 36 && diffDays <= 25) {
			outStr = `${diffDays}天${suffix}`;
			if (dd.includes('%dd')) {
				outStr = dd;
				outStr = outStr.replace('%dd', `${diffDays}`);
			}
		} else if (diffDays >= 26 && diffDays <= 45) {
			outStr = `1个月${suffix}`;
			if (mon.includes('%mon')) {
				outStr = mon;
				outStr = outStr.replace('%mon', '1');
			}
		} else if (diffDays >= 46 && diffMonths <= 10) {
			outStr = `${diffMonths}个月${suffix}`;
			if (mons.includes('%mons')) {
				outStr = mons;
				outStr = outStr.replace('%mons', `${diffMonths}`);
			}
		} else if (diffMonths >= 11 && diffMonths <= 17) {
			outStr = `1年${suffix}`;
			if (y.includes('%y')) {
				outStr = y;
				outStr = outStr.replace('%y', '1');
			}
		} else if (diffMonths >= 18) {
			outStr = `${diffYears}年${suffix}`;
			if (yy.includes('%yy')) {
				outStr = yy;
				outStr = outStr.replace('%yy', `${diffYears}`);
			}
		}

		return outStr;
	};

	private _fromNow(options : FromToOptions) : string {
		return this._fromOrto(new Date(), options);
	}

	fromNow() : string

	// #ifndef APP-HARMONY
	fromNow(options : FromToOptions | null) : string {
		return this._fromNow(options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions)
	}
	// #endif
	// #ifdef APP-HARMONY
	fromNow(options ?: FromToOptions | null) : string {
		return this._fromNow(options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions)
	}
	// #endif

	private _from(dayjs : IKuxDayjs, options : FromToOptions) : string {
		return this._fromOrto(dayjs.d, options);
	}

	from(dayjs : IKuxDayjs) : string

	// #ifndef APP-HARMONY
	from(dayjs : IKuxDayjs, options : FromToOptions | null) : string {
		return this._from(dayjs, options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions);
	}
	// #endif
	// #ifdef APP-HARMONY
	from(dayjs : IKuxDayjs, options ?: FromToOptions | null) : string {
		return this._from(dayjs, options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions);
	}
	// #endif

	private _toNow(options : FromToOptions) : string {
		return this._fromOrto(new Date(), options);
	}

	toNow() : string

	// #ifndef APP-HARMONY
	toNow(options : FromToOptions | null) : string {
		return this._toNow(options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions);
	}
	// #endif
	// #ifdef APP-HARMONY
	toNow(options ?: FromToOptions | null) : string {
		return this._toNow(options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions);
	}
	// #endif

	private _to(date: IKuxDayjs, options : FromToOptions) : string {
		return this._fromOrto(date.d, options);
	}

	to(date: IKuxDayjs) : string

	// #ifndef APP-HARMONY
	to(date: IKuxDayjs, options : FromToOptions | null) : string {
		return this._to(date, options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions);
	}
	// #endif
	// #ifdef APP-HARMONY
	to(date: IKuxDayjs, options ?: FromToOptions | null) : string {
		return this._to(date, options ?? {
			isSuffix: false,
			relativeTime: {
				s: '',
				m: '',
				mm: '',
				h: '',
				hh: '',
				d: '',
				dd: '',
				mon: '',
				mons: '',
				y: '',
				yy: ''
			}
		} as FromToOptions);
	}
	// #endif

	/**
	 * Unix时间戳（毫秒）
	 * @description 返回当前实例的 UNIX 时间戳，13位数字，毫秒
	 */
	valueOf() : number {
		return this.d.getTime();
	}

	/**
	 * Unix时间戳
	 * @description 返回当前实例的 UNIX 时间戳，10位数字，秒。
	 */
	unix() : number {
		return Math.floor(this.valueOf() / 1000);
	}

	/**
	 * 是否闰年
	 * @description 查询 KuxDayjs 对象的年份是否是闰年
	 * @returns {boolean}
	 * @example
	 * const date = dayjs('2000-01-01');
	 * console.log(date.isLeapYear()); // 输出 true
	 */
	isLeapYear() : boolean {
		return (this.dd.year % 4 == 0 && this.dd.year % 100 != 0) || this.dd.year % 400 == 0;
	}

	/**
	 * 获取月天数
	 * @description 获取当前月份包含的天数
	 * @example
	 * const date = dayjs('2023-12-12');
	 * console.log(date.daysInMonth()); // 输出 31
	 */
	daysInMonth() : number {

		// 如果是闰年，2月有 29 天
		if (this.dd.month == 2 && this.isLeapYear()) {
			return 29;
		}

		return MONTH_DAYS[this.dd.month - 1];
	}

	/**
	 * 转Date
	 * @description 从KuxDayjs中获取原生的Date对象
	 */
	toDate() : Date {
		return this.d;
	}

	/**
	 * 转数组
	 * @description 返回一个包含各个时间信息的 Array
	 * @example
	 * const datetime = dayjs('2023-12-13 10:16:18');
	 * console.log(datetime.toArray()); // 输出 [2023,12,13,10,16,18,0]
	 */
	toArray() : number[] {
		return Array(this.dd.year, this.dd.month, this.dd.date, this.dd.hour, this.dd.minute, this.dd.second, this.dd.millisecond);
	}

	/**
	 * 转JSON
	 * @description 序列化为 ISO 8601 格式的字符串
	 * @example
	 * const datetime = dayjs('2023-12-13 10:16:18');
	 * console.log(datetime.toJSON()); // 输出 2023-12-13T10:16:18.000Z
	 */
	toJSON() : string {
		const year = `${this.dd.year}`.padStart(2, '0');
		const month = `${this.dd.month}`.padStart(2, '0');
		const date = `${this.dd.date}`.padStart(2, '0');
		const hours = `${this.dd.hour}`.padStart(2, '0');
		const minutes = `${this.dd.minute}`.padStart(2, '0');
		const seconds = `${this.dd.second}`.padStart(2, '0');
		const milliseconds = `${this.dd.millisecond}`.padStart(3, '0');

		return `${year}-${month}-${date}T${hours}:${minutes}:${seconds}.${milliseconds}Z`;
	}

	/**
	 * 转对象
	 * @description 返回包含时间信息的 Object
	 * @example
	 * const datetime = dayjs('2023-12-13 10:16:18');
	 * console.log(datetime.toObject()); // 输出 {"date":13,"hours":10,"milliseconds":0,"minutes":16,"months":12,"seconds":18,"years":2023}
	 */
	toObject() : DatetimeOptions {
		return {
			years: this.dd.year,
			months: this.dd.month,
			date: this.dd.date,
			hours: this.dd.hour,
			minutes: this.dd.minute,
			seconds: this.dd.second,
			milliseconds: this.dd.millisecond
		} as DatetimeOptions;
	}

	/**
	 * 转字符串
	 * @description 返回包含时间信息的"RFC 822" 或 "RFC 5322" 格式字符串
	 * @example
	 * const datetime = dayjs('2023-12-13 10:16:18');
	 * console.log(datetime.toRFCString()); // 输出 Wed, 13 Dec 2023 10:16:18 GMT
	 */
	toRFCString() : string {
		const weekday = WEEKDAYS[this.toDate().getDay()];
		const year = `${this.dd.year}`;
		const month = MONTHS[this.toDate().getMonth()];
		const day = `${this.dd.date}`.padStart(2, '0');
		const hours = `${this.dd.hour}`.padStart(2, '0');
		const minutes = `${this.dd.minute}`.padStart(2, '0');
		const seconds = `${this.dd.second}`.padStart(2, '0');

		return `${weekday}, ${day} ${month} ${year} ${hours}:${minutes}:${seconds} GMT`;
	}

	private _isGetDate(dayjs : IKuxDayjs, unit : DiffUnit = 'ms') : Date {
		let date : Date;

		const year = dayjs.dd.year;
		const month = dayjs.dd.month;
		const day = dayjs.dd.date;
		const hour = dayjs.dd.hour;
		const minute = dayjs.dd.minute;
		const second = dayjs.dd.second;
		const millsecond = dayjs.dd.millisecond;

		if (unit == 'year' || unit == 'y') {
			date = new Date(year, 0, 0, 0, 0, 0, 0);
		} else if (unit == 'month' || unit == 'M') {
			date = new Date(year, month - 1);
		} else if (unit == 'day' || unit == 'd') {
			date = new Date(year, month - 1, day);
		} else if (unit == 'hour' || unit == 'h') {
			date = new Date(year, month - 1, day, hour);
		} else if (unit == 'minute' || unit == 'm') {
			date = new Date(year, month - 1, day, hour, minute);
		} else if (unit == 'second' || unit == 's') {
			date = new Date(year, month - 1, day, hour, minute, second);
		} else {
			date = new Date(year, month - 1, day, hour, minute, second, millsecond);
		}

		return date;
	}

	private _isBefore(datetime : string, unit : DiffUnit) : boolean {
		const dayjs = this.clone().dayjs(datetime);
		const date1 = this._isGetDate(dayjs, unit);
		// const date2 = this._isGetDate(this.clone(), unit);

		return this.d.getTime() < date1.getTime();
	}

	isBefore(datetime : string) : boolean

	// #ifndef APP-HARMONY
	isBefore(datetime : string, unit : DiffUnit | null) : boolean {
		return this._isBefore(datetime, unit ?? 'ms');
	}
	// #endif
	// #ifdef APP-HARMONY
	isBefore(datetime : string, unit ?: DiffUnit | null) : boolean {
		return this._isBefore(datetime, unit ?? 'ms');
	}
	// #endif

	private _isSame(datetime : string, unit : DatetimeUnit) : boolean {
		const dayjs = this.clone().dayjs(datetime);
		const date1 = this._isGetDate(dayjs, unit);
		// const date2 = this._isGetDate(this.clone());
		if (unit == 'y' || unit == 'year') {
			return this.d.getFullYear() == date1.getFullYear();
		}
		
		if (unit == 'month' || unit == 'M') {
			return this.d.getMonth() == date1.getMonth();
		}
		
		if (unit == 'day' || unit == 'd') {
			return this.d.getDate() == date1.getDate();
		}
		
		if (unit == 'hour' || unit == 'h') {
			return this.d.getHours() == date1.getHours();
		}
		
		if (unit == 'minute' || unit == 'm') {
			return this.d.getMinutes() == date1.getMinutes();
		}
		
		if (unit == 'second' || unit == 's') {
			return this.d.getSeconds() == date1.getSeconds();
		}

		return this.d.getTime() == date1.getTime();
	}

	isSame(datetime : string) : boolean

	// #ifndef APP-HARMONY
	isSame(datetime : string, unit : DatetimeUnit | null) : boolean {
		return this._isSame(datetime, unit ?? 'ms');
	}
	// #endif
	// #ifdef APP-HARMONY
	isSame(datetime : string, unit ?: DatetimeUnit | null) : boolean {
		return this._isSame(datetime, unit ?? 'ms');
	}
	// #endif

	private _isAfter(datetime : string, unit : DatetimeUnit) : boolean {
		const dayjs = this.clone().dayjs(datetime);
		const date1 = this._isGetDate(dayjs, unit);
		// const date2 = this._isGetDate(this.clone(), unit);

		return this.d.getTime() > date1.getTime();
	}

	isAfter(datetime : string) : boolean

	// #ifndef APP-HARMONY
	isAfter(datetime : string, unit : DatetimeUnit | null) : boolean {
		return this._isAfter(datetime, unit ?? 'ms');
	}
	// #endif
	// #ifdef APP-HARMONY
	isAfter(datetime : string, unit ?: DatetimeUnit | null) : boolean {
		return this._isAfter(datetime, unit ?? 'ms');
	}
	// #endif

	private _isSameOrBefore(datetime : string, unit : DatetimeUnit) : boolean {
		const dayjs = this.clone().dayjs(datetime);
		const date1 = this._isGetDate(dayjs, unit);
		// const date2 = this._isGetDate(this.clone(), unit);

		const time1 = date1.getTime();
		const time2 = this.d.getTime();
		
		if (unit == 'y' || unit == 'year') {
			return this.d.getFullYear() <= dayjs.dd.year;
		}
		
		if (unit == 'month' || unit == 'M') {
			return this.d.getMonth() <= date1.getMonth();
		}
		
		if (unit == 'day' || unit == 'd') {
			return this.d.getDate() <= date1.getDate();
		}
		
		if (unit == 'hour' || unit == 'h') {
			return this.d.getHours() <= date1.getHours();
		}
		
		if (unit == 'minute' || unit == 'm') {
			return this.d.getMinutes() <= date1.getMinutes();
		}
		
		if (unit == 'second' || unit == 's') {
			return this.d.getSeconds() <= date1.getSeconds();
		}

		return time2 <= time1;
	}

	isSameOrBefore(datetime : string) : boolean

	// #ifndef APP-HARMONY
	isSameOrBefore(datetime : string, unit : DatetimeUnit | null) : boolean {
		return this._isSameOrBefore(datetime, unit ?? 'ms');
	}
	// #endif
	// #ifdef APP-HARMONY
	isSameOrBefore(datetime : string, unit ?: DatetimeUnit | null) : boolean {
		return this._isSameOrBefore(datetime, unit ?? 'ms');
	}
	// #endif

	private _isSameOrAfter(datetime : string, unit : DatetimeUnit) : boolean {
		const dayjs = this.clone().dayjs(datetime);
		const date1 = this._isGetDate(dayjs, unit);
		// const date2 = this._isGetDate(this.clone(), unit);

		const time1 = date1.getTime();
		const time2 = this.d.getTime();
		
		if (unit == 'y' || unit == 'year') {
			return this.d.getFullYear() >= dayjs.dd.year;
		}
		
		if (unit == 'month' || unit == 'M') {
			return this.d.getMonth() >= date1.getMonth();
		}
		
		if (unit == 'day' || unit == 'd') {
			return this.d.getDate() >= date1.getDate();
		}
		
		if (unit == 'hour' || unit == 'h') {
			return this.d.getHours() >= date1.getHours();
		}
		
		if (unit == 'minute' || unit == 'm') {
			return this.d.getMinutes() >= date1.getMinutes();
		}
		
		if (unit == 'second' || unit == 's') {
			return this.d.getSeconds() >= date1.getSeconds();
		}

		return time2 >= time1;
	}

	isSameOrAfter(datetime : string) : boolean

	// #ifndef APP-HARMONY
	isSameOrAfter(datetime : string, unit : DatetimeUnit | null) : boolean {
		return this._isSameOrAfter(datetime, unit ?? 'ms');
	}
	// #endif
	// #ifdef APP-HARMONY
	isSameOrAfter(datetime : string, unit ?: DatetimeUnit | null) : boolean {
		return this._isSameOrAfter(datetime, unit ?? 'ms');
	}
	// #endif

	private _isBetween(datetime1 : string, datetime2 : string, unit : DatetimeUnit, contains : IsBetweenContains) : boolean {
		const dayjs1 = this.clone().dayjs(datetime1);
		const date1 = this._isGetDate(dayjs1, unit);

		const dayjs2 = this.dayjs(datetime2);
		const date2 = this._isGetDate(dayjs2, unit);

		// const date3 = this._isGetDate(this.clone(), unit);

		const time1 = date1.getTime();
		const time2 = date2.getTime();
		const time3 = this.d.getTime();

		// 向前包含
		if (contains == '[') {
			return time3 >= time1 && time3 < time2;
		}

		// 向后包含
		if (contains == ']') {
			return time3 > time1 && time3 <= time2;
		}

		// 前后都包含
		if (contains == '[]') {
			return time3 >= time1 && time3 <= time2;
		}

		// 前后都不包含
		return time3 > time1 && time3 < time2;
	}

	isBetween(datetime1 : string, datetime2 : string) : boolean

	isBetween(datetime1 : string, datetime2 : string, unit : DatetimeUnit | null) : boolean

	// #ifndef APP-HARMONY
	isBetween(datetime1 : string, datetime2 : string, unit : DatetimeUnit | null, contains : IsBetweenContains | null) : boolean {
		return this._isBetween(datetime1, datetime2, unit ?? 'ms', contains ?? '');
	}
	
	// #endif
	// #ifdef APP-HARMONY
	isBetween(datetime1 : string, datetime2 : string, unit ?: DatetimeUnit | null, contains ?: IsBetweenContains | null) : boolean {
		return this._isBetween(datetime1, datetime2, unit ?? 'ms', contains ?? '');
	}
	
	// #endif
	/**
	 * 是否是Dayjs
	 * @description 这表示一个变量是否为 KuxDayjs 对象
	 * @param {any} dayjs 判断的对象
	 * @returns {boolean}
	 * @example
	 * const now = dayjs();
	 * console.log(now.isDayjs(dayjs())); // 输出 true
	 * console.log(now.isDayjs(new Date())); // 输出 false
	 */
	isDayjs(dayjs : any) : boolean {
		// #ifndef APP-ANDROID
		return dayjs instanceof KuxDayjs;
		// #endif
		// #ifdef APP-ANDROID
		return dayjs instanceof IKuxDayjs;
		// #endif
	}
};

/**
 * 创建的KuxDayjs实例
 * @param {string} date 日期时间戳字符串，如果是想初始化时间戳可以直接把时间戳通过字符串形式传入。时间戳为毫秒形式
 * @param {boolean} isTimestamp 是否是时间戳格式
 * @param {boolean} isCST 是否是中国标准时间，既UTC时间+8小时，`isTimestamp` 为 `true` 时生效，默认为 `true`
 * @returns KuxDayjs实例
 */
export function dayjs(date : string = '', isTimestamp : boolean = false, isCST : boolean = true) : IKuxDayjs {
	return new KuxDayjs(date, isTimestamp, isCST);
};

// 导出类型
// export * from '../utssdk/interface';