/**
 * MobileRolesTab — mobile full-screen variant of RolesTab. Rendered
 * by RolesTab when SelectionStore.isMobileViewport is true. Hosted
 * inside MobileServerSettings, so the top bar + body chrome come
 * from there — this component only renders the tab contents and
 * uses the shared `useMobileSettingsNav` context to push the top
 * bar title / back handler when the user opens a specific role's
 * editor screen.
 *
 * Layout follows the Fluxer mobile reference (see reference images
 * in chat):
 *   List view  — search, helper text, @everyone card, "Roles — N"
 *                header with Create shortcut, then a rounded card
 *                of every custom role with a trailing caret.
 *   Editor view — role name input, color picker card, power level
 *                slider card, abilities readout, delete button.
 *
 * Core CRUD + dirty tracking is intentionally inlined here (instead
 * of shared with desktop RoleEditor) because the mobile layout
 * rearranges controls enough that a mobile=true prop would bloat
 * the desktop JSX. The underlying RoleManager calls are identical.
 */
import { observer } from 'mobx-react-lite';
import { useEffect, useMemo, useState } from 'react';
import {
	CaretRight,
	CheckCircle,
	MagnifyingGlass,
	Plus,
	XCircle,
} from '@phosphor-icons/react';
import { RoleManager } from '@brycord/matrix-client';
import type { Role, PowerLevelAbilities } from '@brycord/matrix-client';
import { MAX_ROLES_PER_SERVER } from '@brycord/constants';
import RoleStore from '@app/stores/RoleStore';
import { useMobileSettingsNav } from './MobileServerSettings';
import styles from './MobileRolesTab.module.css';

interface MobileRolesTabProps {
	serverId: string;
}

const COLOR_SWATCHES: Array<{ hex: string; name: string }> = [
	{ hex: '#99AAB5', name: 'Default' },
	{ hex: '#1ABC9C', name: 'Teal' },
	{ hex: '#2ECC71', name: 'Green' },
	{ hex: '#3498DB', name: 'Blue' },
	{ hex: '#9B59B6', name: 'Purple' },
	{ hex: '#E91E63', name: 'Magenta' },
	{ hex: '#F1C40F', name: 'Yellow' },
	{ hex: '#E67E22', name: 'Orange' },
	{ hex: '#E74C3C', name: 'Red' },
	{ hex: '#95A5A6', name: 'Gray' },
	{ hex: '#607D8B', name: 'Slate' },
];

const HEX_REGEX = /^#[0-9a-fA-F]{6}$/;

/**
 * Build a roleId → member-count map for the given server in one pass
 * over `memberRolesBySpace`. Used by the list view to show a
 * "3 Members" subtitle on each role row. @everyone is excluded
 * because it's never stored in the per-member assignment index.
 */
function useMemberCounts(serverId: string): Record<string, number> {
	return useMemo(() => {
		const assignments = RoleStore.memberRolesBySpace[serverId] ?? {};
		const counts: Record<string, number> = {};
		for (const roleIds of Object.values(assignments)) {
			for (const id of roleIds) {
				counts[id] = (counts[id] ?? 0) + 1;
			}
		}
		return counts;
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [serverId, RoleStore.memberRolesBySpace[serverId]]);
}

export const MobileRolesTab = observer(function MobileRolesTab({
	serverId,
}: MobileRolesTabProps) {
	const [editingRoleId, setEditingRoleId] = useState<string | null>(null);
	const [search, setSearch] = useState('');
	const [error, setError] = useState<string | null>(null);
	const [creating, setCreating] = useState(false);

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

	const memberCounts = useMemberCounts(serverId);

	const allRoles = RoleStore.getRoles(serverId);
	const editableRoles = allRoles
		.filter((r) => r.id !== 'everyone')
		.sort((a, b) => b.position - a.position);
	const everyone = allRoles.find((r) => r.id === 'everyone');

	const filteredRoles = useMemo(() => {
		if (!search.trim()) return editableRoles;
		const q = search.toLowerCase();
		return editableRoles.filter((r) => r.name.toLowerCase().includes(q));
	}, [editableRoles, search]);

	const editingRole: Role | undefined = editingRoleId
		? allRoles.find((r) => r.id === editingRoleId)
		: undefined;

	// Fall back to the list view if the role being edited was deleted
	// from another session or just now by this component.
	useEffect(() => {
		if (editingRoleId && !editingRole) setEditingRoleId(null);
	}, [editingRoleId, editingRole]);

	// Tell MobileServerSettings to swap the top bar title / back
	// button while the editor is open. Cleared on unmount + when the
	// editor closes.
	const nav = useMobileSettingsNav();
	useEffect(() => {
		if (!editingRole) {
			nav.setSubTitle(null);
			nav.setSubSubtitle(null);
			nav.setSubBackHandler(null);
			return;
		}
		nav.setSubTitle(editingRole.name);
		nav.setSubSubtitle('Role');
		nav.setSubBackHandler(() => () => setEditingRoleId(null));
		return () => {
			nav.setSubTitle(null);
			nav.setSubSubtitle(null);
			nav.setSubBackHandler(null);
		};
	}, [editingRole, nav]);

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

	const handleCreate = async () => {
		if (creating) return;
		if (editableRoles.length >= MAX_ROLES_PER_SERVER) {
			setError(`A server can have at most ${MAX_ROLES_PER_SERVER} roles.`);
			return;
		}
		setCreating(true);
		setError(null);
		try {
			const role = await RoleManager.getInstance().createRole(serverId, {
				name: 'New Role',
				powerLevel: 0,
			});
			RoleStore.handleRoleCreated(serverId, role);
			setEditingRoleId(role.id);
		} catch (err: any) {
			setError(err?.message || 'Failed to create role.');
		} finally {
			setCreating(false);
		}
	};

	if (editingRole) {
		return (
			<MobileRoleEditor
				key={editingRole.id}
				serverId={serverId}
				role={editingRole}
				readOnly={editingRole.id === 'everyone'}
				onDeleted={() => setEditingRoleId(null)}
			/>
		);
	}

	return (
		<div className={styles.root}>
			<div className={styles.searchBar}>
				<MagnifyingGlass
					size={18}
					weight="regular"
					className={styles.searchIcon}
				/>
				<input
					type="text"
					className={styles.searchInput}
					placeholder="Search"
					value={search}
					onChange={(e) => setSearch(e.target.value)}
				/>
			</div>

			<p className={styles.helperText}>
				Use roles to group your server members and assign permissions.
			</p>

			{everyone && (
				<div className={styles.everyoneCard}>
					<button
						type="button"
						className={styles.roleRow}
						onClick={() => setEditingRoleId('everyone')}
					>
						<div className={styles.roleAvatar}>
							<span
								className={styles.roleAvatarDot}
								style={{ backgroundColor: 'var(--text-primary-muted)' }}
							/>
						</div>
						<div className={styles.roleRowText}>
							<span className={styles.roleRowName}>@everyone</span>
							<span className={styles.roleRowSubtitle}>
								Default permissions for all server members
							</span>
						</div>
						<CaretRight
							size={16}
							weight="bold"
							className={styles.roleRowCaret}
						/>
					</button>
				</div>
			)}

			<div className={styles.rolesHeader}>
				<span className={styles.rolesHeaderTitle}>
					Roles — {editableRoles.length}
				</span>
				<button
					type="button"
					className={styles.rolesHeaderCreate}
					onClick={handleCreate}
					disabled={creating || editableRoles.length >= MAX_ROLES_PER_SERVER}
				>
					<Plus size={14} weight="bold" />
					Create
				</button>
			</div>

			{filteredRoles.length === 0 ? (
				<div className={styles.emptyState}>
					{search.trim()
						? 'No roles match your search.'
						: 'No roles yet. Tap "Create" to add one.'}
				</div>
			) : (
				<div className={styles.rolesCard}>
					{filteredRoles.map((role) => {
						const count = memberCounts[role.id] ?? 0;
						return (
							<button
								key={role.id}
								type="button"
								className={styles.roleRow}
								onClick={() => setEditingRoleId(role.id)}
							>
								<div className={styles.roleAvatar}>
									<span
										className={styles.roleAvatarDot}
										style={{
											backgroundColor:
												role.color || 'var(--text-primary-muted)',
										}}
									/>
								</div>
								<div className={styles.roleRowText}>
									<span
										className={styles.roleRowName}
										style={role.color ? { color: role.color } : undefined}
									>
										{role.name}
									</span>
									<span className={styles.roleRowSubtitle}>
										{count} {count === 1 ? 'Member' : 'Members'} · PL{' '}
										{role.powerLevel}
									</span>
								</div>
								<CaretRight
									size={16}
									weight="bold"
									className={styles.roleRowCaret}
								/>
							</button>
						);
					})}
				</div>
			)}

			{error && <div className={styles.error}>{error}</div>}
		</div>
	);
});

// ── Editor ──────────────────────────────────────────────────────────

const ABILITY_LABELS: Array<{ key: keyof PowerLevelAbilities; label: string }> = [
	{ key: 'canSendMessages', label: 'Send messages' },
	{ key: 'canInvite', label: 'Invite members' },
	{ key: 'canRenameNicknames', label: 'Rename other members' },
	{ key: 'canRedact', label: "Delete others' messages" },
	{ key: 'canKick', label: 'Kick members' },
	{ key: 'canBan', label: 'Ban members' },
	{ key: 'canSendState', label: 'Send room state events' },
	{ key: 'canRenameChannels', label: 'Rename channels' },
	{ key: 'canManageRoles', label: 'Manage roles' },
	{ key: 'canEditPowerLevels', label: 'Edit server power levels' },
];

interface MobileRoleEditorProps {
	serverId: string;
	role: Role;
	readOnly?: boolean;
	onDeleted: () => void;
}

const MobileRoleEditor = observer(function MobileRoleEditor({
	serverId,
	role,
	readOnly,
	onDeleted,
}: MobileRoleEditorProps) {
	const [name, setName] = useState(role.name);
	const [color, setColor] = useState<string | undefined>(role.color);
	const [powerLevel, setPowerLevel] = useState(role.powerLevel);
	const [saving, setSaving] = useState(false);
	const [deleting, setDeleting] = useState(false);
	const [status, setStatus] = useState<
		{ type: 'success' | 'error'; message: string } | null
	>(null);
	const [confirmDelete, setConfirmDelete] = useState(false);

	useEffect(() => {
		setName(role.name);
		setColor(role.color);
		setPowerLevel(role.powerLevel);
		setStatus(null);
		setConfirmDelete(false);
	}, [role.id]);

	const abilities: PowerLevelAbilities = useMemo(
		() => RoleManager.getInstance().describePowerLevel(serverId, powerLevel),
		[serverId, powerLevel],
	);

	const trimmedName = name.trim();
	const isDirty =
		trimmedName !== role.name ||
		(color ?? undefined) !== (role.color ?? undefined) ||
		powerLevel !== role.powerLevel;
	const nameValid = trimmedName.length > 0 && trimmedName.length <= 32;
	const canSave = isDirty && nameValid && !saving && !readOnly;

	const handleSave = async () => {
		if (!canSave) return;
		setSaving(true);
		setStatus(null);
		try {
			await RoleManager.getInstance().updateRole(serverId, role.id, {
				name: trimmedName,
				color,
				powerLevel,
			});
			RoleStore.handleRoleUpdated(serverId, {
				...role,
				name: trimmedName,
				color,
				powerLevel,
			});
			setStatus({ type: 'success', message: 'Role saved.' });
		} catch (err: any) {
			setStatus({
				type: 'error',
				message: err?.message || 'Failed to save role.',
			});
		} finally {
			setSaving(false);
		}
	};

	const handleDelete = async () => {
		if (readOnly || deleting) return;
		if (!confirmDelete) {
			setConfirmDelete(true);
			return;
		}
		setDeleting(true);
		setStatus(null);
		try {
			await RoleManager.getInstance().deleteRole(serverId, role.id);
			RoleStore.handleRoleDeleted(serverId, role.id);
			onDeleted();
		} catch (err: any) {
			setStatus({
				type: 'error',
				message: err?.message || 'Failed to delete role.',
			});
			setDeleting(false);
		}
	};

	if (readOnly) {
		return (
			<div className={styles.editorRoot}>
				<div className={styles.abilities}>
					<div className={styles.abilitiesHeader}>
						@everyone is the baseline role every member has. Its abilities
						come from the server's default power level thresholds, not
						from a per-role configuration.
					</div>
				</div>
				<AbilitiesReadout
					powerLevel={0}
					abilities={RoleManager.getInstance().describePowerLevel(serverId, 0)}
				/>
			</div>
		);
	}

	return (
		<div className={styles.editorRoot}>
			<div>
				<div className={styles.fieldLabel}>Role name</div>
				<div className={styles.inputCard}>
					<input
						type="text"
						value={name}
						onChange={(e) => setName(e.target.value)}
						maxLength={40}
						placeholder="new role"
					/>
				</div>
			</div>

			<div className={styles.groupCard}>
				<div className={styles.stackedRow}>
					<div className={styles.groupRowLeft}>
						<span className={styles.groupRowLabel}>Role Color</span>
						<span className={styles.groupRowSublabel}>
							{color ? color : 'No color'}
						</span>
					</div>
					<div className={styles.swatchRow}>
						<button
							type="button"
							className={`${styles.swatch} ${styles.swatchNone} ${!color ? styles.swatchActive : ''}`}
							onClick={() => setColor(undefined)}
							aria-label="No color"
						>
							<XCircle size={14} weight="bold" />
						</button>
						{COLOR_SWATCHES.map((s) => (
							<button
								key={s.hex}
								type="button"
								className={`${styles.swatch} ${color === s.hex ? styles.swatchActive : ''}`}
								style={{ backgroundColor: s.hex }}
								onClick={() => setColor(s.hex)}
								aria-label={s.name}
							/>
						))}
					</div>
					<input
						type="text"
						className={styles.hexInput}
						value={color ?? ''}
						placeholder="#5865F2"
						onChange={(e) => {
							const val = e.target.value;
							if (val === '' || HEX_REGEX.test(val)) {
								setColor(val || undefined);
							} else if (val.startsWith('#') && val.length <= 7) {
								setColor(val);
							}
						}}
					/>
				</div>

				<div className={styles.stackedRow}>
					<div className={styles.powerHeader}>
						<span className={styles.groupRowLabel}>Power Level</span>
						<span className={styles.powerValue}>{powerLevel}</span>
					</div>
					<input
						type="range"
						min={0}
						max={100}
						value={powerLevel}
						onChange={(e) => setPowerLevel(Number(e.target.value))}
						className={styles.slider}
					/>
					<p className={styles.powerHint}>
						Power level determines what members with this role can do
						at the Matrix protocol layer. Multiple roles can share the
						same power level.
					</p>
				</div>
			</div>

			<AbilitiesReadout powerLevel={powerLevel} abilities={abilities} />

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

			<button
				type="button"
				className={styles.saveButton}
				onClick={handleSave}
				disabled={!canSave}
			>
				{saving ? 'Saving…' : 'Save Role'}
			</button>

			<div className={styles.deleteCard}>
				<button
					type="button"
					className={styles.deleteButton}
					onClick={handleDelete}
					disabled={deleting}
				>
					{confirmDelete ? 'Tap again to confirm delete' : 'Delete Role'}
				</button>
			</div>
		</div>
	);
});

function AbilitiesReadout({
	powerLevel,
	abilities,
}: {
	powerLevel: number;
	abilities: PowerLevelAbilities;
}) {
	return (
		<div className={styles.abilities}>
			<div className={styles.abilitiesHeader}>
				At power level <strong>{powerLevel}</strong>, members can:
			</div>
			<ul className={styles.abilitiesList}>
				{ABILITY_LABELS.map(({ key, label }) => {
					const allowed = abilities[key];
					return (
						<li
							key={key}
							className={allowed ? styles.abilityOn : styles.abilityOff}
						>
							{allowed ? (
								<CheckCircle size={14} weight="fill" />
							) : (
								<XCircle size={14} weight="fill" />
							)}
							<span>{label}</span>
						</li>
					);
				})}
			</ul>
		</div>
	);
}
