/*
 * Copyright (C) 2026 Fluxer Contributors
 *
 * This file is part of Fluxer.
 *
 * Fluxer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Fluxer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
 */

import {
	MAX_BIO_LENGTH_NON_PREMIUM,
	MAX_BIO_LENGTH_PREMIUM,
	MAX_BOOKMARKS_NON_PREMIUM,
	MAX_BOOKMARKS_PREMIUM,
	MAX_FAVORITE_MEMES_NON_PREMIUM,
	MAX_FAVORITE_MEMES_PREMIUM,
	MAX_GUILDS_NON_PREMIUM,
	MAX_GUILDS_PREMIUM,
	MAX_MESSAGE_LENGTH_NON_PREMIUM,
	MAX_MESSAGE_LENGTH_PREMIUM,
	UserFlags,
} from '~/Constants';
import DeveloperOptionsStore from '~/stores/DeveloperOptionsStore';
import RuntimeConfigStore from '~/stores/RuntimeConfigStore';
import {getAttachmentMaxSize} from '~/utils/AttachmentUtils';
import * as SnowflakeUtils from '~/utils/SnowflakeUtils';

export type BackupCode = Readonly<{
	code: string;
	consumed: boolean;
}>;

export type UserProfile = Readonly<{
	bio: string | null;
	banner: string | null;
	banner_color?: number | null;
	pronouns: string | null;
	accent_color: string | null;
}>;

export type UserPartial = Readonly<{
	id: string;
	username: string;
	discriminator: string;
	global_name?: string | null;
	avatar: string | null;
	avatar_color?: number | null;
	bot?: boolean;
	system?: boolean;
	flags: number;
}>;

export type RequiredAction =
	| 'REQUIRE_VERIFIED_EMAIL'
	| 'REQUIRE_REVERIFIED_EMAIL'
	| 'REQUIRE_VERIFIED_PHONE'
	| 'REQUIRE_REVERIFIED_PHONE'
	| 'REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE'
	| 'REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE'
	| 'REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE'
	| 'REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE';

export type UserPrivate = Readonly<
	UserPartial &
		UserProfile & {
			email: string | null;
			mfa_enabled: boolean;
			phone: string | null;
			authenticator_types: Array<number>;
			verified: boolean;
			premium_type: number | null;
			premium_since: string | null;
			premium_until: string | null;
			premium_will_cancel: boolean;
			premium_billing_cycle: string | null;
			premium_lifetime_sequence: number | null;
			premium_badge_hidden: boolean;
			premium_badge_masked: boolean;
			premium_badge_timestamp_hidden: boolean;
			premium_badge_sequence_hidden: boolean;
			premium_purchase_disabled: boolean;
			premium_enabled_override: boolean;
			password_last_changed_at: string | null;
			required_actions: Array<RequiredAction> | null;
			nsfw_allowed: boolean;
			pending_manual_verification: boolean;
			pending_bulk_message_deletion: {
				scheduled_at: string;
				channel_count: number;
				message_count: number;
			} | null;
			has_dismissed_premium_onboarding: boolean;
			has_ever_purchased: boolean;
			has_unread_gift_inventory: boolean;
			unread_gift_inventory_count: number;
			used_mobile_client: boolean;
		}
>;

export type User = Readonly<UserPartial & Partial<UserPrivate>>;

export type PendingBulkMessageDeletion = Readonly<{
	scheduledAt: Date;
	channelCount: number;
	messageCount: number;
}>;

export class UserRecord {
	readonly id: string;
	readonly username: string;
	readonly discriminator: string;
	readonly globalName: string | null;
	readonly avatar: string | null;
	readonly avatarColor?: number | null;
	readonly bot: boolean;
	readonly system: boolean;
	readonly flags: number;
	private readonly _email?: string | null;
	readonly bio?: string | null;
	readonly banner?: string | null;
	readonly bannerColor?: number | null;
	readonly pronouns?: string | null;
	readonly accentColor?: string | null;
	readonly mfaEnabled?: boolean;
	readonly phone?: string | null;
	readonly authenticatorTypes?: Array<number>;
	private readonly _verified?: boolean;
	private readonly _premiumType?: number | null;
	private readonly _premiumSince?: Date | null;
	private readonly _premiumUntil?: Date | null;
	private readonly _premiumWillCancel?: boolean;
	private readonly _premiumBillingCycle?: string | null;
	readonly premiumLifetimeSequence?: number | null;
	readonly premiumBadgeHidden?: boolean;
	readonly premiumBadgeMasked?: boolean;
	readonly premiumBadgeTimestampHidden?: boolean;
	readonly premiumBadgeSequenceHidden?: boolean;
	readonly premiumPurchaseDisabled?: boolean;
	readonly premiumEnabledOverride?: boolean;
	readonly passwordLastChangedAt?: Date | null;
	readonly requiredActions?: Array<RequiredAction> | null;
	readonly pendingManualVerification?: boolean;
	readonly pendingBulkMessageDeletion: PendingBulkMessageDeletion | null;
	private readonly _nsfwAllowed?: boolean;
	readonly hasDismissedPremiumOnboarding?: boolean;
	private readonly _hasEverPurchased?: boolean;
	private readonly _hasUnreadGiftInventory?: boolean;
	private readonly _unreadGiftInventoryCount?: number;
	private readonly _usedMobileClient?: boolean;

	constructor(user: User) {
		this.id = user.id;
		this.username = user.username;
		this.discriminator = user.discriminator;
		this.globalName = user.global_name ?? null;
		this.avatar = user.avatar;
		if ('avatar_color' in user) this.avatarColor = user.avatar_color;
		this.bot = user.bot ?? false;
		this.system = user.system ?? false;
		this.flags = user.flags;

		if ('email' in user) this._email = user.email;
		if ('bio' in user) this.bio = user.bio;
		if ('banner' in user) this.banner = user.banner;
		if ('banner_color' in user) this.bannerColor = user.banner_color;
		if ('pronouns' in user) this.pronouns = user.pronouns;
		if ('accent_color' in user) this.accentColor = user.accent_color;
		if ('mfa_enabled' in user) this.mfaEnabled = user.mfa_enabled;
		if ('phone' in user) this.phone = user.phone;
		if ('authenticator_types' in user) this.authenticatorTypes = user.authenticator_types;
		if ('verified' in user) this._verified = user.verified;
		if ('premium_type' in user) this._premiumType = user.premium_type;
		if ('premium_since' in user) this._premiumSince = user.premium_since ? new Date(user.premium_since) : null;
		if ('premium_until' in user) this._premiumUntil = user.premium_until ? new Date(user.premium_until) : null;
		if ('premium_will_cancel' in user) this._premiumWillCancel = user.premium_will_cancel;
		if ('premium_billing_cycle' in user) this._premiumBillingCycle = user.premium_billing_cycle;
		if ('premium_lifetime_sequence' in user) this.premiumLifetimeSequence = user.premium_lifetime_sequence;
		if ('premium_badge_hidden' in user) this.premiumBadgeHidden = user.premium_badge_hidden;
		if ('premium_badge_masked' in user) this.premiumBadgeMasked = user.premium_badge_masked;
		if ('premium_badge_timestamp_hidden' in user)
			this.premiumBadgeTimestampHidden = user.premium_badge_timestamp_hidden;
		if ('premium_badge_sequence_hidden' in user) this.premiumBadgeSequenceHidden = user.premium_badge_sequence_hidden;
		if ('premium_purchase_disabled' in user) this.premiumPurchaseDisabled = user.premium_purchase_disabled;
		if ('premium_enabled_override' in user) this.premiumEnabledOverride = user.premium_enabled_override;
		if ('password_last_changed_at' in user)
			this.passwordLastChangedAt = user.password_last_changed_at ? new Date(user.password_last_changed_at) : null;
		if ('required_actions' in user) {
			this.requiredActions = user.required_actions && user.required_actions.length > 0 ? user.required_actions : null;
		}
		if ('pending_manual_verification' in user) this.pendingManualVerification = user.pending_manual_verification;
		if ('pending_bulk_message_deletion' in user && user.pending_bulk_message_deletion) {
			this.pendingBulkMessageDeletion = {
				scheduledAt: new Date(user.pending_bulk_message_deletion.scheduled_at),
				channelCount: user.pending_bulk_message_deletion.channel_count,
				messageCount: user.pending_bulk_message_deletion.message_count,
			};
		} else {
			this.pendingBulkMessageDeletion = null;
		}
		if ('nsfw_allowed' in user) this._nsfwAllowed = user.nsfw_allowed;
		if ('has_dismissed_premium_onboarding' in user)
			this.hasDismissedPremiumOnboarding = user.has_dismissed_premium_onboarding;
		if ('has_ever_purchased' in user) this._hasEverPurchased = user.has_ever_purchased;
		if ('has_unread_gift_inventory' in user) this._hasUnreadGiftInventory = user.has_unread_gift_inventory;
		if ('unread_gift_inventory_count' in user) this._unreadGiftInventoryCount = user.unread_gift_inventory_count;
		if ('used_mobile_client' in user) this._usedMobileClient = user.used_mobile_client;
	}

	get email(): string | null | undefined {
		if (DeveloperOptionsStore.unclaimedAccountOverride === true) {
			return null;
		}
		return this._email;
	}

	get verified(): boolean | undefined {
		const verifiedOverride = DeveloperOptionsStore.emailVerifiedOverride;
		if (verifiedOverride != null) {
			return verifiedOverride;
		}
		return this._verified;
	}

	get premiumType(): number | null {
		const override = DeveloperOptionsStore.premiumTypeOverride;
		return override != null ? override : (this._premiumType ?? null);
	}

	get premiumSince(): Date | null | undefined {
		const override = DeveloperOptionsStore.premiumSinceOverride;
		return override != null ? override : this._premiumSince;
	}

	get premiumUntil(): Date | null | undefined {
		const override = DeveloperOptionsStore.premiumUntilOverride;
		return override != null ? override : this._premiumUntil;
	}

	get premiumBillingCycle(): string | null | undefined {
		const override = DeveloperOptionsStore.premiumBillingCycleOverride;
		return override != null ? override : this._premiumBillingCycle;
	}

	get premiumWillCancel(): boolean | undefined {
		const override = DeveloperOptionsStore.premiumWillCancelOverride;
		return override != null ? override : this._premiumWillCancel;
	}

	getPendingBulkMessageDeletion(): PendingBulkMessageDeletion | null {
		return this.pendingBulkMessageDeletion;
	}

	hasPendingBulkMessageDeletion(): boolean {
		return this.pendingBulkMessageDeletion != null;
	}

	get hasEverPurchased(): boolean | undefined {
		const override = DeveloperOptionsStore.hasEverPurchasedOverride;
		return override != null ? override : this._hasEverPurchased;
	}

	get hasUnreadGiftInventory(): boolean | undefined {
		const override = DeveloperOptionsStore.hasUnreadGiftInventoryOverride;
		return override != null ? override : this._hasUnreadGiftInventory;
	}

	get unreadGiftInventoryCount(): number | undefined {
		const override = DeveloperOptionsStore.unreadGiftInventoryCountOverride;
		return override != null ? override : this._unreadGiftInventoryCount;
	}

	get nsfwAllowed(): boolean | undefined {
		return this._nsfwAllowed;
	}

	get usedMobileClient(): boolean | undefined {
		return this._usedMobileClient;
	}

	withUpdates(updates: Partial<User>): UserRecord {
		const baseFields: UserPartial = {
			id: updates.id ?? this.id,
			username: updates.username ?? this.username,
			discriminator: updates.discriminator ?? this.discriminator,
			avatar: 'avatar' in updates ? (updates.avatar as string | null) : this.avatar,
			bot: updates.bot ?? this.bot,
			system: updates.system ?? this.system,
			flags: updates.flags ?? this.flags,
		};

		const pendingBulkMessageDeletionValue =
			'pending_bulk_message_deletion' in updates
				? updates.pending_bulk_message_deletion
				: this.pendingBulkMessageDeletion
					? {
							scheduled_at: this.pendingBulkMessageDeletion.scheduledAt.toISOString(),
							channel_count: this.pendingBulkMessageDeletion.channelCount,
							message_count: this.pendingBulkMessageDeletion.messageCount,
						}
					: null;

		const privateFields: Partial<UserPrivate> = {
			...(this._email !== undefined || updates.email !== undefined ? {email: updates.email ?? this._email} : {}),
			...(this.bio !== undefined || 'bio' in updates
				? {bio: 'bio' in updates && updates.bio !== undefined ? (updates.bio as string | null) : this.bio}
				: {}),
			...(this.avatarColor !== undefined || 'avatar_color' in updates
				? {
						avatar_color:
							'avatar_color' in updates && updates.avatar_color !== undefined
								? (updates.avatar_color as number | null)
								: this.avatarColor,
					}
				: {}),
			...(this.banner !== undefined || 'banner' in updates
				? {
						banner:
							'banner' in updates && updates.banner !== undefined ? (updates.banner as string | null) : this.banner,
					}
				: {}),
			...(this.bannerColor !== undefined || 'banner_color' in updates
				? {
						banner_color:
							'banner_color' in updates && updates.banner_color !== undefined
								? (updates.banner_color as number | null)
								: this.bannerColor,
					}
				: {}),
			...(this.globalName !== undefined || 'global_name' in updates
				? {
						global_name:
							'global_name' in updates && updates.global_name !== undefined
								? (updates.global_name as string | null)
								: this.globalName,
					}
				: {}),
			...(this.pronouns !== undefined || 'pronouns' in updates
				? {
						pronouns:
							'pronouns' in updates && updates.pronouns !== undefined
								? (updates.pronouns as string | null)
								: this.pronouns,
					}
				: {}),
			...(this.accentColor !== undefined || 'accent_color' in updates
				? {
						accent_color:
							'accent_color' in updates && updates.accent_color !== undefined
								? (updates.accent_color as string | null)
								: this.accentColor,
					}
				: {}),
			...(this.mfaEnabled !== undefined || updates.mfa_enabled !== undefined
				? {mfa_enabled: updates.mfa_enabled ?? this.mfaEnabled}
				: {}),
			...(this.phone !== undefined || 'phone' in updates
				? {phone: 'phone' in updates && updates.phone !== undefined ? (updates.phone as string | null) : this.phone}
				: {}),
			...(this.authenticatorTypes !== undefined || updates.authenticator_types !== undefined
				? {authenticator_types: updates.authenticator_types ?? this.authenticatorTypes}
				: {}),
			...(this._verified !== undefined || updates.verified !== undefined
				? {verified: updates.verified ?? this._verified}
				: {}),
			...(this._premiumType !== undefined || updates.premium_type !== undefined
				? {premium_type: updates.premium_type ?? this._premiumType}
				: {}),
			...(this._premiumSince !== undefined || updates.premium_since !== undefined
				? {premium_since: updates.premium_since ?? (this._premiumSince ? this._premiumSince.toISOString() : null)}
				: {}),
			...(this._premiumUntil !== undefined || updates.premium_until !== undefined
				? {premium_until: updates.premium_until ?? (this._premiumUntil ? this._premiumUntil.toISOString() : null)}
				: {}),
			...(this._premiumWillCancel !== undefined || updates.premium_will_cancel !== undefined
				? {premium_will_cancel: updates.premium_will_cancel ?? this._premiumWillCancel}
				: {}),
			...(this._premiumBillingCycle !== undefined || updates.premium_billing_cycle !== undefined
				? {premium_billing_cycle: updates.premium_billing_cycle ?? this._premiumBillingCycle}
				: {}),
			...(this.premiumLifetimeSequence !== undefined || updates.premium_lifetime_sequence !== undefined
				? {premium_lifetime_sequence: updates.premium_lifetime_sequence ?? this.premiumLifetimeSequence}
				: {}),
			...(this.premiumBadgeHidden !== undefined || updates.premium_badge_hidden !== undefined
				? {premium_badge_hidden: updates.premium_badge_hidden ?? this.premiumBadgeHidden}
				: {}),
			...(this.premiumBadgeMasked !== undefined || updates.premium_badge_masked !== undefined
				? {premium_badge_masked: updates.premium_badge_masked ?? this.premiumBadgeMasked}
				: {}),
			...(this.premiumBadgeTimestampHidden !== undefined || updates.premium_badge_timestamp_hidden !== undefined
				? {premium_badge_timestamp_hidden: updates.premium_badge_timestamp_hidden ?? this.premiumBadgeTimestampHidden}
				: {}),
			...(this.premiumBadgeSequenceHidden !== undefined || updates.premium_badge_sequence_hidden !== undefined
				? {premium_badge_sequence_hidden: updates.premium_badge_sequence_hidden ?? this.premiumBadgeSequenceHidden}
				: {}),
			...(this.premiumPurchaseDisabled !== undefined || updates.premium_purchase_disabled !== undefined
				? {premium_purchase_disabled: updates.premium_purchase_disabled ?? this.premiumPurchaseDisabled}
				: {}),
			...(this.premiumEnabledOverride !== undefined || updates.premium_enabled_override !== undefined
				? {premium_enabled_override: updates.premium_enabled_override ?? this.premiumEnabledOverride}
				: {}),
			...(this.passwordLastChangedAt !== undefined || updates.password_last_changed_at !== undefined
				? {
						password_last_changed_at:
							updates.password_last_changed_at ?? this.passwordLastChangedAt?.toISOString() ?? null,
					}
				: {}),
			...(this.pendingManualVerification !== undefined || updates.pending_manual_verification !== undefined
				? {
						pending_manual_verification: updates.pending_manual_verification ?? this.pendingManualVerification,
					}
				: {}),
			pending_bulk_message_deletion: pendingBulkMessageDeletionValue,
			...(this.requiredActions !== undefined || 'required_actions' in updates
				? {
						required_actions:
							'required_actions' in updates
								? updates.required_actions && (updates.required_actions as Array<RequiredAction>).length > 0
									? (updates.required_actions as Array<RequiredAction>)
									: null
								: this.requiredActions,
					}
				: {}),
			...(this._nsfwAllowed !== undefined || updates.nsfw_allowed !== undefined
				? {nsfw_allowed: updates.nsfw_allowed ?? this._nsfwAllowed}
				: {}),
			...(this.hasDismissedPremiumOnboarding !== undefined || updates.has_dismissed_premium_onboarding !== undefined
				? {
						has_dismissed_premium_onboarding:
							updates.has_dismissed_premium_onboarding ?? this.hasDismissedPremiumOnboarding,
					}
				: {}),
			...(this._hasEverPurchased !== undefined || updates.has_ever_purchased !== undefined
				? {has_ever_purchased: updates.has_ever_purchased ?? this._hasEverPurchased}
				: {}),
			...(this._hasUnreadGiftInventory !== undefined || updates.has_unread_gift_inventory !== undefined
				? {has_unread_gift_inventory: updates.has_unread_gift_inventory ?? this._hasUnreadGiftInventory}
				: {}),
			...(this._unreadGiftInventoryCount !== undefined || updates.unread_gift_inventory_count !== undefined
				? {unread_gift_inventory_count: updates.unread_gift_inventory_count ?? this._unreadGiftInventoryCount}
				: {}),
			...(this._usedMobileClient !== undefined || updates.used_mobile_client !== undefined
				? {used_mobile_client: updates.used_mobile_client ?? this._usedMobileClient}
				: {}),
		};

		return new UserRecord({
			...baseFields,
			...privateFields,
		});
	}

	get displayName(): string {
		return this.globalName || this.username;
	}

	get tag(): string {
		return `${this.username}#${this.discriminator}`;
	}

	get createdAt(): Date {
		return new Date(SnowflakeUtils.extractTimestamp(this.id));
	}

	isPremium(): boolean {
		if (RuntimeConfigStore.isSelfHosted()) {
			return true;
		}
		return this.premiumType != null && this.premiumType > 0;
	}

	get maxGuilds(): number {
		return this.isPremium() ? MAX_GUILDS_PREMIUM : MAX_GUILDS_NON_PREMIUM;
	}

	get maxMessageLength(): number {
		return this.isPremium() ? MAX_MESSAGE_LENGTH_PREMIUM : MAX_MESSAGE_LENGTH_NON_PREMIUM;
	}

	get maxAttachmentSize(): number {
		return getAttachmentMaxSize(this.isPremium());
	}

	get maxBioLength(): number {
		return this.isPremium() ? MAX_BIO_LENGTH_PREMIUM : MAX_BIO_LENGTH_NON_PREMIUM;
	}

	get maxBookmarks(): number {
		return this.isPremium() ? MAX_BOOKMARKS_PREMIUM : MAX_BOOKMARKS_NON_PREMIUM;
	}

	get maxFavoriteMemes(): number {
		return this.isPremium() ? MAX_FAVORITE_MEMES_PREMIUM : MAX_FAVORITE_MEMES_NON_PREMIUM;
	}

	isStaff(): boolean {
		return (this.flags & UserFlags.STAFF) !== 0;
	}

	isClaimed(): boolean {
		return !!this.email;
	}

	equals(other: UserRecord): boolean {
		return (
			this.id === other.id &&
			this.username === other.username &&
			this.discriminator === other.discriminator &&
			this.avatar === other.avatar &&
			this.avatarColor === other.avatarColor &&
			this.bot === other.bot &&
			this.system === other.system &&
			this.flags === other.flags &&
			this._email === other._email &&
			this.bio === other.bio &&
			this.banner === other.banner &&
			this.bannerColor === other.bannerColor &&
			this.pronouns === other.pronouns &&
			this.mfaEnabled === other.mfaEnabled &&
			this.phone === other.phone &&
			JSON.stringify(this.authenticatorTypes) === JSON.stringify(other.authenticatorTypes) &&
			this._verified === other._verified &&
			this._premiumType === other._premiumType &&
			this.premiumSince?.getTime() === other.premiumSince?.getTime() &&
			this.premiumUntil?.getTime() === other.premiumUntil?.getTime() &&
			this.premiumWillCancel === other.premiumWillCancel &&
			this._premiumBillingCycle === other._premiumBillingCycle &&
			this.premiumLifetimeSequence === other.premiumLifetimeSequence &&
			this.premiumBadgeHidden === other.premiumBadgeHidden &&
			this.premiumBadgeMasked === other.premiumBadgeMasked &&
			this.premiumBadgeTimestampHidden === other.premiumBadgeTimestampHidden &&
			this.premiumBadgeSequenceHidden === other.premiumBadgeSequenceHidden &&
			this.premiumPurchaseDisabled === other.premiumPurchaseDisabled &&
			this.premiumEnabledOverride === other.premiumEnabledOverride &&
			this.passwordLastChangedAt?.getTime() === other.passwordLastChangedAt?.getTime() &&
			JSON.stringify(this.requiredActions) === JSON.stringify(other.requiredActions) &&
			this.pendingManualVerification === other.pendingManualVerification &&
			((this.pendingBulkMessageDeletion === null && other.pendingBulkMessageDeletion === null) ||
				(this.pendingBulkMessageDeletion != null &&
					other.pendingBulkMessageDeletion != null &&
					this.pendingBulkMessageDeletion.channelCount === other.pendingBulkMessageDeletion.channelCount &&
					this.pendingBulkMessageDeletion.messageCount === other.pendingBulkMessageDeletion.messageCount &&
					this.pendingBulkMessageDeletion.scheduledAt.getTime() ===
						other.pendingBulkMessageDeletion.scheduledAt.getTime())) &&
			this._nsfwAllowed === other._nsfwAllowed &&
			this.hasDismissedPremiumOnboarding === other.hasDismissedPremiumOnboarding &&
			this._hasUnreadGiftInventory === other._hasUnreadGiftInventory &&
			this._unreadGiftInventoryCount === other._unreadGiftInventoryCount &&
			this._usedMobileClient === other._usedMobileClient
		);
	}

	toJSON(): User {
		const normalizeDate = (value: Date | string | number | null | undefined): string | null => {
			if (value === null || value === undefined) return null;
			const date = value instanceof Date ? value : new Date(value);
			return Number.isNaN(date.getTime()) ? null : date.toISOString();
		};

		const baseFields: UserPartial = {
			id: this.id,
			username: this.username,
			discriminator: this.discriminator,
			global_name: this.globalName,
			avatar: this.avatar,
			bot: this.bot,
			system: this.system,
			flags: this.flags,
		};

		const privateFields: Partial<UserPrivate> = {
			...(this._email !== undefined ? {email: this._email} : {}),
			...(this.bio !== undefined ? {bio: this.bio} : {}),
			...(this.banner !== undefined ? {banner: this.banner} : {}),
			...(this.avatarColor !== undefined ? {avatar_color: this.avatarColor} : {}),
			...(this.bannerColor !== undefined ? {banner_color: this.bannerColor} : {}),
			...(this.pronouns !== undefined ? {pronouns: this.pronouns} : {}),
			...(this.accentColor !== undefined ? {accent_color: this.accentColor} : {}),
			...(this.mfaEnabled !== undefined ? {mfa_enabled: this.mfaEnabled} : {}),
			...(this.phone !== undefined ? {phone: this.phone} : {}),
			...(this.authenticatorTypes !== undefined ? {authenticator_types: this.authenticatorTypes} : {}),
			...(this._verified !== undefined ? {verified: this._verified} : {}),
			...(this._premiumType !== undefined ? {premium_type: this._premiumType} : {}),
			...(this._premiumSince !== undefined ? {premium_since: normalizeDate(this._premiumSince)} : {}),
			...(this._premiumUntil !== undefined ? {premium_until: normalizeDate(this._premiumUntil)} : {}),
			...(this._premiumWillCancel !== undefined ? {premium_will_cancel: this._premiumWillCancel} : {}),
			...(this._premiumBillingCycle !== undefined ? {premium_billing_cycle: this._premiumBillingCycle} : {}),
			...(this.premiumLifetimeSequence !== undefined ? {premium_lifetime_sequence: this.premiumLifetimeSequence} : {}),
			...(this.premiumBadgeHidden !== undefined ? {premium_badge_hidden: this.premiumBadgeHidden} : {}),
			...(this.premiumBadgeMasked !== undefined ? {premium_badge_masked: this.premiumBadgeMasked} : {}),
			...(this.premiumBadgeTimestampHidden !== undefined
				? {premium_badge_timestamp_hidden: this.premiumBadgeTimestampHidden}
				: {}),
			...(this.premiumBadgeSequenceHidden !== undefined
				? {premium_badge_sequence_hidden: this.premiumBadgeSequenceHidden}
				: {}),
			...(this.premiumPurchaseDisabled !== undefined ? {premium_purchase_disabled: this.premiumPurchaseDisabled} : {}),
			...(this.premiumEnabledOverride !== undefined ? {premium_enabled_override: this.premiumEnabledOverride} : {}),
			...(this.passwordLastChangedAt !== undefined
				? {password_last_changed_at: normalizeDate(this.passwordLastChangedAt)}
				: {}),
			...(this.requiredActions !== undefined ? {required_actions: this.requiredActions} : {}),
			...(this.pendingManualVerification !== undefined
				? {pending_manual_verification: this.pendingManualVerification}
				: {}),
			...(this.pendingBulkMessageDeletion !== undefined
				? {
						pending_bulk_message_deletion: this.pendingBulkMessageDeletion
							? {
									scheduled_at: this.pendingBulkMessageDeletion.scheduledAt.toISOString(),
									channel_count: this.pendingBulkMessageDeletion.channelCount,
									message_count: this.pendingBulkMessageDeletion.messageCount,
								}
							: null,
					}
				: {}),
			...(this._nsfwAllowed !== undefined ? {nsfw_allowed: this._nsfwAllowed} : {}),
			...(this.hasDismissedPremiumOnboarding !== undefined
				? {has_dismissed_premium_onboarding: this.hasDismissedPremiumOnboarding}
				: {}),
			...(this._hasUnreadGiftInventory !== undefined ? {has_unread_gift_inventory: this._hasUnreadGiftInventory} : {}),
			...(this._unreadGiftInventoryCount !== undefined
				? {unread_gift_inventory_count: this._unreadGiftInventoryCount}
				: {}),
			...(this._usedMobileClient !== undefined ? {used_mobile_client: this._usedMobileClient} : {}),
		};

		return {
			...baseFields,
			...privateFields,
		};
	}
}
