/**
 * EmojisTab — admin UI for managing the server's MSC2545 image pack.
 * Upload PNG / GIF / WebP images, assign shortcodes, delete existing
 * entries. Gated behind `EmojiPackManager.canManageEmojis` (native
 * Matrix power level check on `im.ponies.room_emotes` state events).
 *
 * Pattern mirrors `RolesTab`: optimistic store updates, tolerant
 * error surfacing, file + shortcode validation before hitting the
 * homeserver.
 */
import { observer } from 'mobx-react-lite';
import { useMemo, useRef, useState } from 'react';
import { Upload, Trash, Plus } from '@phosphor-icons/react';
import { Button } from '@brycord/ui';
import {
	EmojiPackManager,
	MAX_EMOJIS_PER_PACK,
	type CustomEmoji,
} from '@brycord/matrix-client';
import EmojiPackStore from '@app/stores/EmojiPackStore';
import SelectionStore from '@app/stores/SelectionStore';
import { CustomEmojiImage } from '../channel/CustomEmojiImage';
import { MobileEmojisTab } from './MobileEmojisTab';
import styles from './EmojisTab.module.css';

interface EmojisTabProps {
	serverId: string;
}

const SHORTCODE_REGEX = /^[a-z0-9_]{2,30}$/;

export const EmojisTab = observer(function EmojisTab({ serverId }: EmojisTabProps) {
	// Mobile gets a completely different full-screen layout — see
	// MobileEmojisTab. Branch into a thin wrapper component so the
	// desktop hooks below don't run on the mobile path.
	if (SelectionStore.isMobileViewport) {
		return <MobileEmojisTab serverId={serverId} />;
	}
	return <DesktopEmojisTab serverId={serverId} />;
});

const DesktopEmojisTab = observer(function DesktopEmojisTab({ serverId }: EmojisTabProps) {
	const [pendingFile, setPendingFile] = useState<File | null>(null);
	const [pendingPreviewUrl, setPendingPreviewUrl] = useState<string | null>(null);
	const [shortcode, setShortcode] = useState('');
	const [uploading, setUploading] = useState(false);
	const [deletingId, setDeletingId] = useState<string | null>(null);
	const [status, setStatus] = useState<{ type: 'success' | 'error'; message: string } | null>(null);
	const fileInputRef = useRef<HTMLInputElement>(null);

	const canManage = useMemo(() => {
		try {
			return EmojiPackManager.getInstance().canManageEmojis(serverId);
		} catch {
			return false;
		}
	}, [serverId]);

	const pack = EmojiPackStore.getPack(serverId);
	const emojis: CustomEmoji[] = pack?.emojis ?? [];
	const isFull = emojis.length >= MAX_EMOJIS_PER_PACK;

	if (!canManage) {
		return (
			<div className={styles.gate}>
				<h2 className={styles.gateTitle}>Emojis</h2>
				<p className={styles.gateBody}>
					You need permission to manage emojis in this server. Ask an
					admin to grant you a role with a higher power level.
				</p>
			</div>
		);
	}

	const handleFilePick = (e: React.ChangeEvent<HTMLInputElement>) => {
		const file = e.target.files?.[0];
		// Reset the input so the same file can be re-picked after clearing.
		if (fileInputRef.current) fileInputRef.current.value = '';
		if (!file) return;
		setStatus(null);

		if (!file.type.startsWith('image/')) {
			setStatus({ type: 'error', message: 'Emoji must be a PNG, GIF, or WebP image.' });
			return;
		}
		if (file.size > 256 * 1024) {
			setStatus({
				type: 'error',
				message: 'File is too large. Maximum is 256 KB.',
			});
			return;
		}

		if (pendingPreviewUrl) URL.revokeObjectURL(pendingPreviewUrl);
		setPendingFile(file);
		setPendingPreviewUrl(URL.createObjectURL(file));

		// Auto-suggest a shortcode from the filename: strip extension,
		// lowercase, replace non-alphanumerics with underscores, clamp.
		if (!shortcode) {
			const base = file.name.replace(/\.[^.]+$/, '').toLowerCase();
			const cleaned = base.replace(/[^a-z0-9_]/g, '_').slice(0, 30);
			if (cleaned.length >= 2) setShortcode(cleaned);
		}
	};

	const handleUpload = async () => {
		if (!pendingFile) return;
		if (uploading) return;

		const trimmed = shortcode.trim();
		if (!SHORTCODE_REGEX.test(trimmed)) {
			setStatus({
				type: 'error',
				message: 'Shortcode must be 2–30 characters of lowercase letters, digits, or underscores.',
			});
			return;
		}
		if (emojis.some((e) => e.shortcode === trimmed)) {
			setStatus({ type: 'error', message: `An emoji named "${trimmed}" already exists.` });
			return;
		}

		setUploading(true);
		setStatus(null);
		try {
			await EmojiPackManager.getInstance().addEmoji(serverId, trimmed, pendingFile);
			// The RoomState.events listener in MatrixActions will push
			// the new pack to EmojiPackStore on the next tick; clear
			// the local form state immediately for snappy feedback.
			if (pendingPreviewUrl) URL.revokeObjectURL(pendingPreviewUrl);
			setPendingFile(null);
			setPendingPreviewUrl(null);
			setShortcode('');
			setStatus({ type: 'success', message: `Added :${trimmed}:` });
		} catch (err: any) {
			setStatus({ type: 'error', message: err?.message || 'Failed to upload emoji.' });
		} finally {
			setUploading(false);
		}
	};

	const handleRemove = async (emoji: CustomEmoji) => {
		if (deletingId) return;
		if (!window.confirm(`Remove :${emoji.shortcode}: from this server?`)) return;
		setDeletingId(emoji.shortcode);
		setStatus(null);
		try {
			await EmojiPackManager.getInstance().removeEmoji(serverId, emoji.shortcode);
			setStatus({ type: 'success', message: `Removed :${emoji.shortcode}:` });
		} catch (err: any) {
			setStatus({ type: 'error', message: err?.message || 'Failed to remove emoji.' });
		} finally {
			setDeletingId(null);
		}
	};

	const handleClearPending = () => {
		if (pendingPreviewUrl) URL.revokeObjectURL(pendingPreviewUrl);
		setPendingFile(null);
		setPendingPreviewUrl(null);
		setShortcode('');
	};

	return (
		<div className={styles.container}>
			<div className={styles.header}>
				<h2 className={styles.heading}>Server Emojis</h2>
				<span className={styles.count}>
					{emojis.length}/{MAX_EMOJIS_PER_PACK}
				</span>
			</div>
			<p className={styles.description}>
				Upload custom emojis that everyone in this server can use in
				messages and reactions. PNG, GIF, or WebP up to 256&nbsp;KB.
				Animated GIFs play automatically.
			</p>

			{/* Upload row */}
			<div className={styles.uploadRow}>
				<div className={styles.uploadPreview}>
					{pendingPreviewUrl ? (
						<img
							src={pendingPreviewUrl}
							alt="pending emoji preview"
							className={styles.uploadPreviewImage}
							draggable={false}
						/>
					) : (
						<div className={styles.uploadPreviewEmpty}>
							<Upload size={20} />
						</div>
					)}
				</div>
				<div className={styles.uploadFields}>
					<input
						type="text"
						className={styles.shortcodeInput}
						placeholder="shortcode"
						value={shortcode}
						onChange={(e) =>
							setShortcode(e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, ''))
						}
						maxLength={30}
					/>
					<div className={styles.uploadActions}>
						{!pendingFile ? (
							<Button
								variant="secondary"
								size="sm"
								icon={<Upload size={14} />}
								onClick={() => fileInputRef.current?.click()}
								disabled={isFull}
							>
								Choose File
							</Button>
						) : (
							<>
								<Button
									variant="primary"
									size="sm"
									icon={<Plus size={14} weight="bold" />}
									onClick={handleUpload}
									disabled={uploading || !SHORTCODE_REGEX.test(shortcode)}
									loading={uploading}
								>
									{uploading ? 'Uploading…' : 'Add'}
								</Button>
								<Button
									variant="secondary"
									size="sm"
									onClick={handleClearPending}
									disabled={uploading}
								>
									Cancel
								</Button>
							</>
						)}
					</div>
				</div>
			</div>
			<input
				ref={fileInputRef}
				type="file"
				accept="image/png,image/gif,image/webp,image/jpeg"
				onChange={handleFilePick}
				style={{ display: 'none' }}
			/>

			{status && (
				<div
					className={
						status.type === 'error' ? styles.statusError : styles.statusSuccess
					}
				>
					{status.message}
				</div>
			)}

			{/* Existing pack grid */}
			{emojis.length === 0 ? (
				<div className={styles.empty}>
					No custom emojis yet. Upload one above to get started.
				</div>
			) : (
				<div className={styles.grid}>
					{emojis.map((emoji) => (
						<div key={emoji.mxcUrl} className={styles.gridItem}>
							<div className={styles.gridPreview}>
								<CustomEmojiImage
									mxc={emoji.mxcUrl}
									alt={`:${emoji.shortcode}:`}
									title={`:${emoji.shortcode}:`}
									className={styles.gridImage}
									draggable={false}
								/>
							</div>
							<div className={styles.gridLabel} title={`:${emoji.shortcode}:`}>
								:{emoji.shortcode}:
							</div>
							<button
								type="button"
								className={styles.gridRemove}
								onClick={() => handleRemove(emoji)}
								disabled={deletingId === emoji.shortcode}
								aria-label={`Remove :${emoji.shortcode}:`}
							>
								<Trash size={14} weight="fill" />
							</button>
						</div>
					))}
				</div>
			)}
		</div>
	);
});
