/**
 * Matrix client shim.
 *
 * The new UI was built against a Matrix client SDK (`@brycord/matrix-client`).
 * This project uses Convex instead. This file provides stub types and
 * manager classes so the UI compiles. Every component that reads from these
 * stubs must eventually be rewired to use Convex queries/mutations — but
 * having them here lets the big-bang UI replacement compile in one step.
 *
 * Each manager is a singleton exposing `getInstance()` + no-op methods that
 * return sensible empty values (empty arrays, null, false). UI still renders.
 */

// ─── Shared primitive types ───────────────────────────────────────────────

export type ChannelType = 'text' | 'voice' | 'category' | 'dm' | 'group_dm';

export interface Channel {
	id: string;
	roomId: string;
	name: string;
	type: ChannelType;
	topic?: string;
	parentId?: string | null;
	position?: number;
	nsfw?: boolean;
	slowmode?: number;
	icon?: string | null;
	isDM?: boolean;
	avatarUrl?: string | null;
	lastMessageTs?: number;
	memberCount?: number;
	userLimit?: number;
	bitrate?: number;
	rateLimitPerUser?: number;
}

export interface Server {
	id: string;
	name: string;
	icon?: string | null;
	avatarUrl?: string | null;
	memberCount?: number;
	onlineCount?: number;
	ownerId?: string;
	description?: string;
	roomIds?: string[];
}

export interface Member {
	userId: string;
	id: string;
	displayName: string;
	name?: string;
	avatarUrl?: string | null;
	powerLevel?: number;
	roles?: string[];
	presence?: PresenceStatus;
	status?: string;
	accentColor?: string;
	bio?: string;
	joinedAt?: number;
}

export interface Attachment {
	id?: string;
	url: string;
	name: string;
	filename?: string;
	size: number;
	mimeType: string;
	width?: number;
	height?: number;
	duration?: number;
	waveform?: number[];
	thumbnailUrl?: string | null;
	spoiler?: boolean;
	description?: string;
}

export interface Message {
	id: string;
	eventId: string;
	channelId: string;
	senderId: string;
	authorId: string;
	authorName?: string;
	authorAvatarUrl?: string | null;
	content: string;
	body?: string;
	formattedBody?: string;
	timestamp: number;
	editedTimestamp?: number | null;
	attachments?: Attachment[];
	replyToId?: string | null;
	reactions?: MessageReaction[];
	mentions?: string[];
	mentionRoles?: string[];
	pinned?: boolean;
	type?: string;
	isRedacted?: boolean;
	isEncrypted?: boolean;
	isPending?: boolean;
	error?: string | null;
}

export interface MessageReaction {
	key: string;
	count: number;
	userIds: string[];
	me: boolean;
}

export interface CustomEmoji {
	id: string;
	name: string;
	shortcode: string;
	url: string;
	animated?: boolean;
	packId?: string;
}

export interface EmojiPack {
	id: string;
	name: string;
	emojis: CustomEmoji[];
}

export type SavedMediaKind = 'image' | 'video' | 'audio' | 'gif' | 'sticker';

export interface SavedMediaItem {
	id: string;
	kind: SavedMediaKind;
	url: string;
	mimeType?: string;
	name?: string;
	width?: number;
	height?: number;
	addedAt: number;
}

export interface Role {
	id: string;
	name: string;
	color: string;
	position: number;
	permissions: number;
	hoist?: boolean;
	mentionable?: boolean;
	powerLevel?: number;
}

export interface PowerLevelAbilities {
	canKick: boolean;
	canBan: boolean;
	canInvite: boolean;
	canRedact: boolean;
	canSetState: boolean;
	canManageRoles: boolean;
	canManageChannels: boolean;
}

export type PresenceStatus = 'online' | 'idle' | 'dnd' | 'offline' | 'invisible' | 'unavailable';

export interface PollAnswer {
	id: string;
	text: string;
}

export interface Poll {
	id: string;
	question: string;
	answers: PollAnswer[];
	multiple: boolean;
	endsAt?: number;
	votes?: Record<string, string[]>;
}

export interface DeviceTrustInfo {
	deviceId: string;
	userId: string;
	trusted: boolean;
	verified: boolean;
	ed25519Key?: string;
}

export type VoiceConnectionState =
	| 'disconnected'
	| 'connecting'
	| 'connected'
	| 'reconnecting'
	| 'disconnecting'
	| 'failed'
	| 'rejoinable';

export type VoiceErrorReason = 'token' | 'network' | 'permission' | 'unknown';

export interface VoiceError {
	reason: VoiceErrorReason;
	message: string;
}

export interface VoiceParticipantSnapshot {
	userId: string;
	identity: string;
	displayName: string;
	avatarUrl?: string | null;
	isMuted: boolean;
	isDeafened: boolean;
	isSpeaking: boolean;
	isScreenSharing: boolean;
	isCameraOn: boolean;
	isLocal: boolean;
	connectionQuality?: 'excellent' | 'good' | 'poor' | 'lost' | 'unknown';
	volume?: number;
}

// ─── Manager singletons (stubs) ───────────────────────────────────────────

function singleton<T extends object>(factory: () => T): { getInstance(): T } {
	let inst: T | null = null;
	return {
		getInstance() {
			if (!inst) inst = factory();
			return inst;
		},
	};
}

export const MatrixClientManager = singleton(() => ({
	getClient: () => null as any,
	getUserId: () => (typeof localStorage !== 'undefined' ? localStorage.getItem('userId') || '' : ''),
	getDisplayName: () => (typeof localStorage !== 'undefined' ? localStorage.getItem('username') || '' : ''),
	getDeviceId: () => '',
	getHomeserverUrl: () => '',
	isReady: () => true,
	start: async () => {},
	stop: async () => {},
	logout: async () => {},
}));

export const RoomManager = singleton(() => ({
	getRoom: (_id: string): Channel | null => null,
	listRooms: (): Channel[] => [],
	createChannel: async (_args: unknown): Promise<string> => '',
	renameChannel: async (_id: string, _name: string) => {},
	deleteChannel: async (_id: string) => {},
	setTopic: async (_id: string, _topic: string) => {},
	getPowerLevel: (_id: string) => 0,
	getStateDefault: (_id: string) => 0,
	canManageChannel: (_id: string) => true,
}));

export const MemberManager = singleton(() => ({
	getMember: (_roomId: string, _userId: string): Member | null => null,
	listMembers: (_roomId: string): Member[] => [],
	getMemberSnapshot: async (_roomId: string, _userId: string): Promise<Member | null> => null,
	setNickname: async (_roomId: string, _userId: string, _nickname: string) => {},
	kick: async (_roomId: string, _userId: string, _reason?: string) => {},
	ban: async (_roomId: string, _userId: string, _reason?: string) => {},
}));

export const MessageManager = singleton(() => ({
	listMessages: (_channelId: string): Message[] => [],
	sendMessage: async (_channelId: string, _body: string): Promise<string> => '',
	editMessage: async (_channelId: string, _id: string, _body: string) => {},
	deleteMessage: async (_channelId: string, _id: string) => {},
	addReaction: async (_channelId: string, _id: string, _key: string) => {},
	removeReaction: async (_channelId: string, _id: string, _key: string) => {},
}));

export const MediaManager = singleton(() => ({
	resolveMxcToObjectUrl: async (_mxc: string): Promise<string | null> => null,
	resolveMxcThumbnailToObjectUrl: async (
		_mxc: string,
		_w: number,
		_h: number,
		_mode?: string,
	): Promise<string | null> => null,
	uploadFile: async (_file: File): Promise<string> => '',
	getFileUrl: (_url: string): string => _url,
}));

export const CryptoManager = singleton(() => ({
	isReady: () => true,
	getDeviceTrustInfo: (_userId: string, _deviceId: string): DeviceTrustInfo | null => null,
	verifyDevice: async (_userId: string, _deviceId: string) => {},
	exportRoomKeys: async (): Promise<string> => '',
	importRoomKeys: async (_json: string) => {},
}));

export const PinsManager = singleton(() => ({
	getPinned: (_channelId: string): Message[] => [],
	pin: async (_channelId: string, _messageId: string) => {},
	unpin: async (_channelId: string, _messageId: string) => {},
}));

export const SavedMediaManager = singleton(() => ({
	list: (_kind?: SavedMediaKind): SavedMediaItem[] => [],
	save: async (_item: SavedMediaItem) => {},
	remove: async (_id: string) => {},
	has: (_url: string): boolean => false,
}));

export const FriendManager = singleton(() => ({
	listFriends: (): Member[] => [],
	listPending: (): Member[] => [],
	listIgnored: (): Member[] => [],
	addFriend: async (_userId: string) => {},
	acceptFriend: async (_userId: string) => {},
	ignoreFriend: async (_userId: string) => {},
	removeFriend: async (_userId: string) => {},
	unignoreFriend: async (_userId: string) => {},
}));

export const PersonalNotesManager = singleton(() => ({
	getRoomId: (): string | null => null,
	ensureRoom: async (): Promise<string> => '',
}));

export const SpaceManager = singleton(() => ({
	listSpaces: (): Server[] => [],
	getSpace: (_id: string): Server | null => null,
	createSpace: async (_name: string): Promise<string> => '',
	leaveSpace: async (_id: string) => {},
}));

export const PresenceManager = singleton(() => ({
	getPresence: (_userId: string): PresenceStatus => 'offline',
	setPresence: async (_status: PresenceStatus) => {},
}));

export const RoleManager = singleton(() => ({
	listRoles: (_serverId: string): Role[] => [],
	getRole: (_serverId: string, _roleId: string): Role | null => null,
	createRole: async (_serverId: string, _name: string): Promise<string> => '',
	updateRole: async (_serverId: string, _roleId: string, _patch: Partial<Role>) => {},
	deleteRole: async (_serverId: string, _roleId: string) => {},
	assignRole: async (_serverId: string, _userId: string, _roleId: string) => {},
	unassignRole: async (_serverId: string, _userId: string, _roleId: string) => {},
	getMemberRoles: (_serverId: string, _userId: string): string[] => [],
	getAbilitiesForMember: (_serverId: string, _userId: string): PowerLevelAbilities => ({
		canKick: false,
		canBan: false,
		canInvite: false,
		canRedact: false,
		canSetState: false,
		canManageRoles: false,
		canManageChannels: false,
	}),
}));

export const VoiceManager = singleton(() => ({
	connect: async (_channelId: string) => {},
	disconnect: async () => {},
	isConnected: (): boolean => false,
	getConnectionState: (): VoiceConnectionState => 'disconnected',
	getParticipants: (_channelId: string): VoiceParticipantSnapshot[] => [],
	setMuted: async (_muted: boolean) => {},
	setDeafened: async (_deafened: boolean) => {},
	setCameraOn: async (_on: boolean) => {},
	setScreenShare: async (_on: boolean) => {},
}));

export const EmojiPackManager = singleton(() => ({
	listPacks: (): EmojiPack[] => [],
	getPack: (_id: string): EmojiPack | null => null,
}));

export const VoiceModerationManager = singleton(() => ({
	serverMute: async (_userId: string) => {},
	serverUnmute: async (_userId: string) => {},
	moveMember: async (_userId: string, _channelId: string) => {},
	disconnectMember: async (_userId: string) => {},
}));

// ─── Constants / helpers ──────────────────────────────────────────────────

export const MAX_EMOJIS_PER_PACK = 100;

/** Classify a MIME type into a SavedMediaKind. */
export function classifyMediaKind(mimeType: string): SavedMediaKind {
	if (mimeType.startsWith('image/gif')) return 'gif';
	if (mimeType.startsWith('image/')) return 'image';
	if (mimeType.startsWith('video/')) return 'video';
	if (mimeType.startsWith('audio/')) return 'audio';
	return 'image';
}

/** Parse a LiveKit participant identity in the format `@user:server:device`. */
export function parseMatrixUserFromIdentity(identity: string): { userId: string; deviceId: string } | null {
	if (!identity) return null;
	const lastColon = identity.lastIndexOf(':');
	if (lastColon === -1) return null;
	return {
		userId: identity.slice(0, lastColon),
		deviceId: identity.slice(lastColon + 1),
	};
}
