import { RoomManager } from '@brycord/matrix-client';
import { Check, GlobeHemisphereWest, Lock, UsersThree } from '@phosphor-icons/react';
/**
 * AccessPicker — three-option "who can join" picker for a channel
 * or category. Mirrors Element's "Invite only / Space members /
 * Anyone" control and writes the corresponding `m.room.join_rules`
 * state event via `RoomManager.setChannelAccess`.
 *
 * Reads the current access on mount. Writes are optimistic —
 * selection updates immediately; on server rejection we roll back
 * and show an inline error. Disabled when the caller passes
 * `disabled` (e.g., the user lacks `state_default` PL in the
 * target room).
 */
import { useEffect, useState } from 'react';
import styles from './AccessPicker.module.css';

export type AccessMode = 'invite' | 'space_members' | 'public';

interface AccessPickerProps {
	/** The channel or category whose access we're editing. */
	roomId: string;
	/** Parent space — used when writing the `restricted` allow list. */
	spaceId: string;
	/** When true, every option is non-interactive. */
	disabled?: boolean;
}

interface OptionDescriptor {
	value: AccessMode;
	icon: React.ReactNode;
	title: string;
	description: string;
}

const OPTIONS: OptionDescriptor[] = [
	{
		value: 'invite',
		icon: <Lock size={20} weight="fill" />,
		title: 'Invite Only',
		description: 'Only invited members can see and join this channel.',
	},
	{
		value: 'space_members',
		icon: <UsersThree size={20} weight="fill" />,
		title: 'Space Members',
		description: 'Anyone in the server can join. Recommended.',
	},
	{
		value: 'public',
		icon: <GlobeHemisphereWest size={20} weight="fill" />,
		title: 'Anyone',
		description: 'Anyone with a link can join, even without a server invite.',
	},
];

export function AccessPicker({ roomId, spaceId, disabled = false }: AccessPickerProps) {
	const [current, setCurrent] = useState<AccessMode | 'other' | null>(null);
	const [saving, setSaving] = useState(false);
	const [error, setError] = useState<string | null>(null);

	// Read the current access on mount and whenever the target
	// room changes. Synchronous — reads from matrix-js-sdk's
	// in-memory room state.
	useEffect(() => {
		const mode = RoomManager.getInstance().getChannelAccess(roomId, spaceId);
		setCurrent(mode);
	}, [roomId, spaceId]);

	const handleSelect = async (next: AccessMode) => {
		if (disabled || saving || next === current) return;
		const previous = current;
		// Optimistic — flip the UI immediately, roll back on error.
		setCurrent(next);
		setSaving(true);
		setError(null);
		try {
			await RoomManager.getInstance().setChannelAccess(roomId, next, spaceId);
		} catch (err: any) {
			setCurrent(previous);
			setError(err?.message || 'Failed to update access.');
		} finally {
			setSaving(false);
		}
	};

	// If the room has join rules we don't recognise (e.g. `knock`
	// or a `restricted` allow list pointing at a different room),
	// surface that rather than silently overwriting the config.
	const isCustom = current === 'other';

	return (
		<div className={styles.root}>
			<div className={styles.sectionLabel}>Channel Access</div>
			<p className={styles.sectionDescription}>
				Control who can join this channel. Existing members always keep their access — this only affects new joins.
			</p>

			{isCustom && (
				<p className={styles.customNotice}>
					Custom join rules are set on this channel. Pick an option below to replace them.
				</p>
			)}

			<div className={styles.optionList}>
				{OPTIONS.map((opt) => {
					const isSelected = current === opt.value;
					return (
						<button
							key={opt.value}
							type="button"
							className={`${styles.option} ${isSelected ? styles.optionSelected : ''}`}
							onClick={() => handleSelect(opt.value)}
							disabled={disabled || saving}
						>
							<span className={styles.optionIcon}>{opt.icon}</span>
							<span className={styles.optionBody}>
								<span className={styles.optionTitle}>{opt.title}</span>
								<span className={styles.optionDescription}>{opt.description}</span>
							</span>
							{isSelected && (
								<span className={styles.optionCheck}>
									<Check size={14} weight="bold" />
								</span>
							)}
						</button>
					);
				})}
			</div>

			{disabled && <p className={styles.disabledHint}>You need a higher role to change access.</p>}

			{error && <p className={`${styles.status} ${styles.statusError}`}>{error}</p>}
		</div>
	);
}
