import type { DisplayRestrictions } from '@atcute/bluesky-moderation';
import type { Handle } from '@atcute/lexicons';

// \u2705 = ✅
// \u2713 = ✓
// \u2714 = ✔
// \u2611 = ☑
const CHECK_MARKS_RE = /[\u2705\u2713\u2714\u2611]/gu;
// oxlint-disable-next-line no-control-regex -- stripping control characters is the point
const CONTROL_CHARS_RE = /[\u0000-\u001F\u007F-\u009F\u061C\u200E\u200F\u202A-\u202E\u2066-\u2069]/g;
const MULTIPLE_SPACES_RE = /[\s][\s\u200B]+/g;

export function sanitizeDisplayName(str: string, moderation?: DisplayRestrictions): string {
	if (moderation && moderation.blurs.length > 0) {
		return '';
	}
	if (typeof str === 'string') {
		return str
			.replace(CHECK_MARKS_RE, '')
			.replace(CONTROL_CHARS_RE, '')
			.replace(MULTIPLE_SPACES_RE, ' ')
			.trim();
	}
	return '';
}

/**
 * the name to show for a profile: its sanitized display name, falling back to the handle when the profile has
 * no display name.
 *
 * moderation applies only to the display name — a profile whose display name is blurred renders as empty
 * rather than falling back to the handle.
 *
 * @param profile the profile to name
 * @param options `bareHandle` drops the `@` from the handle fallback; `moderation` blurs the display name
 * @returns the display name, the handle, or an empty string when moderation blurs the name
 */
export function profileDisplayName(
	profile: { displayName?: string; handle: Handle },
	options?: { bareHandle?: boolean; moderation?: DisplayRestrictions },
): string {
	if (profile.displayName) {
		return sanitizeDisplayName(profile.displayName, options?.moderation);
	}
	return options?.bareHandle ? profile.handle : `@${profile.handle}`;
}

export function combinedDisplayName({
	handle,
	displayName,
}: {
	handle?: Handle;
	displayName?: string;
}): string {
	if (!handle) {
		return '';
	}
	return displayName ? `${sanitizeDisplayName(displayName)} (@${handle})` : `@${handle}`;
}

/** whether a handle is the `handle.invalid` sentinel the appview returns for an unresolvable handle. */
export function isInvalidHandle(handle: string): boolean {
	return handle === 'handle.invalid';
}
