<script lang="ts">
	import { onMount } from 'svelte';
	import { goto } from '$app/navigation';
	import { getSupabase } from '$lib/supabase';
	import { currentUser } from '$lib/stores/auth';
	import { currentCollective, collectiveMembers, userCollectives } from '$lib/stores/collective';
	import Avatar from '$lib/components/Avatar.svelte';
	import type { FeatureFlags, SectionKey } from '@colectivo/types';
	import { SECTION_KEYS } from '@colectivo/types';
	import { setCollectiveFeature } from '$lib/stores/features';
	import * as m from '$lib/paraglide/messages';

	type Member = {
		user_id: string;
		role: 'admin' | 'member' | 'guest';
		display_name: string;
		avatar_type: 'initials' | 'emoji' | 'upload';
		avatar_emoji: string | null;
		avatar_url: string | null;
	};

	let members = $state<Member[]>([]);
	let loading = $state(true);
	let error = $state<string | null>(null);

	let inviteRole = $state<'member' | 'guest'>('member');
	let generatedLink = $state<string | null>(null);
	let generating = $state(false);
	let copied = $state(false);

	const myRole = $derived(members.find((m) => m.user_id === $currentUser?.id)?.role);
	const isAdmin = $derived(myRole === 'admin');

	onMount(() => {
		// Re-run loadMembers() whenever the active collective resolves or
		// changes. onMount alone races with the auth listener's first
		// `currentCollective.set(...)` on cold navigations (hit /collective/manage
		// directly in a new tab or after a page reload) and we end up with an
		// empty list because the first fetch was short-circuited by
		// `$currentCollective == null`.
		const unsub = currentCollective.subscribe((c) => {
			if (c) void loadMembers();
		});
		return unsub;
	});

	async function loadMembers() {
		if (!$currentCollective) return;
		loading = true;

		const { data, error: fetchError } = await getSupabase()
			.from('collective_members')
			.select(`
				user_id, role,
				users(display_name, avatar_type, avatar_emoji, avatar_url)
			`)
			.eq('collective_id', $currentCollective.id)
			.order('joined_at');

		if (fetchError) {
			error = fetchError.message;
			loading = false;
			return;
		}

		members = (data ?? []).map((row) => {
			const u = row.users as { display_name: string; avatar_type: string; avatar_emoji: string | null; avatar_url: string | null } | null;
			return {
				user_id: row.user_id,
				role: row.role as Member['role'],
				display_name: u?.display_name ?? '',
				avatar_type: (u?.avatar_type ?? 'initials') as Member['avatar_type'],
				avatar_emoji: u?.avatar_emoji ?? null,
				avatar_url: u?.avatar_url ?? null
			};
		});
		collectiveMembers.set(members.map((m) => ({ ...m, collective_id: $currentCollective!.id })));
		loading = false;
	}

	async function changeRole(userId: string, newRole: 'admin' | 'member' | 'guest') {
		if (!$currentCollective) return;
		const { error: updateError } = await getSupabase()
			.from('collective_members')
			.update({ role: newRole })
			.eq('collective_id', $currentCollective.id)
			.eq('user_id', userId);

		if (updateError) {
			error = updateError.message;
			return;
		}
		members = members.map((m) => m.user_id === userId ? { ...m, role: newRole } : m);
	}

	async function removeMember(userId: string) {
		if (!$currentCollective) return;
		const { error: deleteError } = await getSupabase()
			.from('collective_members')
			.delete()
			.eq('collective_id', $currentCollective.id)
			.eq('user_id', userId);

		if (deleteError) {
			error = deleteError.message;
			return;
		}
		members = members.filter((m) => m.user_id !== userId);
	}

	async function generateInviteLink() {
		if (!$currentCollective) return;
		generating = true;
		generatedLink = null;

		const { data, error: insertError } = await getSupabase()
			.from('collective_invitations')
			.insert({
				collective_id: $currentCollective.id,
				role: inviteRole,
				created_by: $currentUser!.id
			})
			.select('token')
			.single();

		if (insertError || !data) {
			error = insertError?.message ?? 'Failed to generate link.';
			generating = false;
			return;
		}

		generatedLink = `${window.location.origin}/invitation/${data.token}`;
		generating = false;
	}

	async function copyLink() {
		if (!generatedLink) return;
		await navigator.clipboard.writeText(generatedLink);
		copied = true;
		setTimeout(() => (copied = false), 2000);
	}

	const ROLES: Array<'admin' | 'member' | 'guest'> = ['admin', 'member', 'guest'];

	function roleLabel(role: 'admin' | 'member' | 'guest'): string {
		if (role === 'admin') return m.role_admin();
		if (role === 'member') return m.role_member();
		return m.role_guest();
	}

	// ── Fase 10.2: rename + change emoji (admin only) ───────────────────────
	let nameDraft = $state('');
	let nameSaving = $state(false);
	let nameSaved = $state(false);
	let emojiPickerOpen = $state(false);

	const EMOJI_OPTIONS = [
		'🏠', '🏡', '🏢', '🏣', '🏤', '🏥', '🏦', '🏨',
		'🏩', '🏪', '🏫', '🏬', '🏭', '🏯', '🏰', '🗼',
		'🌆', '🌇', '🌃', '🌉', '🏙️', '⛺', '🌴', '🌵'
	];

	// Keep nameDraft in sync with $currentCollective.
	$effect(() => {
		if ($currentCollective) nameDraft = $currentCollective.name;
	});

	async function saveCollectiveName() {
		if (!$currentCollective || !isAdmin) return;
		const trimmed = nameDraft.trim();
		if (!trimmed || trimmed === $currentCollective.name) return;
		nameSaving = true;
		const { data, error: updErr } = await getSupabase()
			.from('collectives')
			.update({ name: trimmed })
			.eq('id', $currentCollective.id)
			.select('id, name, emoji, created_at, feature_flags')
			.single();
		nameSaving = false;
		if (updErr || !data) {
			error = updErr?.message ?? 'Failed to save name.';
			return;
		}
		applyCollectivePatch(
			data as {
				id: string;
				name: string;
				emoji: string;
				created_at: string;
				feature_flags: import('@colectivo/types').FeatureFlags;
			}
		);
		nameSaved = true;
		setTimeout(() => (nameSaved = false), 1500);
	}

	function onNameKeydown(e: KeyboardEvent) {
		if (e.key === 'Enter') {
			e.preventDefault();
			void saveCollectiveName();
		} else if (e.key === 'Escape') {
			e.preventDefault();
			if ($currentCollective) nameDraft = $currentCollective.name;
		}
	}

	async function selectEmoji(emoji: string) {
		emojiPickerOpen = false;
		if (!$currentCollective || !isAdmin || emoji === $currentCollective.emoji) return;
		const { data, error: updErr } = await getSupabase()
			.from('collectives')
			.update({ emoji })
			.eq('id', $currentCollective.id)
			.select('id, name, emoji, created_at, feature_flags')
			.single();
		if (updErr || !data) {
			error = updErr?.message ?? 'Failed to save emoji.';
			return;
		}
		applyCollectivePatch(
			data as {
				id: string;
				name: string;
				emoji: string;
				created_at: string;
				feature_flags: import('@colectivo/types').FeatureFlags;
			}
		);
	}

	function applyCollectivePatch(c: {
		id: string;
		name: string;
		emoji: string;
		created_at: string;
		feature_flags: import('@colectivo/types').FeatureFlags;
	}) {
		currentCollective.set(c);
		userCollectives.update((list) => list.map((it) => (it.id === c.id ? c : it)));
	}

	// ── Fase 12.4.2 — collective section visibility (admin only) ────────────
	function sectionLabel(section: SectionKey): string {
		if (section === 'lists') return m.section_label_lists();
		if (section === 'tasks') return m.section_label_tasks();
		if (section === 'notes') return m.section_label_notes();
		return m.section_label_search();
	}

	function collectiveFlag(section: SectionKey): boolean {
		const flags = (($currentCollective?.feature_flags ?? {}) as FeatureFlags);
		// Missing key → ON (the collective has "no opinion" and the user layer
		// can take over). Equivalent to section_enabled's collective coalesce.
		return flags[section] ?? true;
	}

	async function toggleCollectiveSection(section: SectionKey) {
		if (!isAdmin) return;
		const next = !collectiveFlag(section);
		try {
			await setCollectiveFeature(section, next);
		} catch {
			// optimistic mutation already rolled back inside the helper
		}
	}

	// ── Fase 10.3: dissolve collective (CU-H08) ─────────────────────────────
	let dissolveOpen = $state(false);
	let dissolveConfirmInput = $state('');
	let dissolveError = $state<string | null>(null);
	let dissolveInFlight = $state(false);
	let listsCount = $state(0);
	let tasksCount = $state(0);
	let notesCount = $state(0);

	const dissolveConfirmReady = $derived(
		!!$currentCollective && dissolveConfirmInput === $currentCollective.name
	);

	async function openDissolve() {
		if (!$currentCollective || !isAdmin) return;
		dissolveOpen = true;
		dissolveConfirmInput = '';
		dissolveError = null;
		// Best-effort counts; failures fall back to 0.
		const supabase = getSupabase();
		const [l, t, n] = await Promise.all([
			supabase
				.from('shopping_lists')
				.select('id', { head: true, count: 'exact' })
				.eq('collective_id', $currentCollective.id),
			supabase
				.from('tasks')
				.select('id', { head: true, count: 'exact' })
				.in(
					'list_id',
					(
						await supabase
							.from('task_lists')
							.select('id')
							.eq('collective_id', $currentCollective.id)
					).data?.map((r) => r.id) ?? []
				),
			supabase
				.from('notes')
				.select('id', { head: true, count: 'exact' })
				.eq('collective_id', $currentCollective.id)
		]);
		listsCount = l.count ?? 0;
		tasksCount = t.count ?? 0;
		notesCount = n.count ?? 0;
	}

	function closeDissolve() {
		dissolveOpen = false;
		dissolveConfirmInput = '';
		dissolveError = null;
	}

	async function confirmDissolve() {
		if (!$currentCollective || !dissolveConfirmReady || dissolveInFlight) return;
		const target = $currentCollective;
		dissolveInFlight = true;
		dissolveError = null;

		const { error: rpcErr } = await getSupabase().rpc('dissolve_collective', {
			p_collective_id: target.id
		});
		if (rpcErr) {
			dissolveInFlight = false;
			dissolveError = rpcErr.message;
			return;
		}

		// Update local stores. Pick the next collective or redirect to onboarding.
		const remaining = $userCollectives.filter((c) => c.id !== target.id);
		userCollectives.set(remaining);
		dissolveOpen = false;
		dissolveInFlight = false;

		if (remaining.length > 0) {
			const next = remaining[0];
			currentCollective.set(next);
			localStorage.setItem('activeCollectiveId', next.id);
			await goto('/lists');
		} else {
			currentCollective.set(null);
			localStorage.removeItem('activeCollectiveId');
			await goto('/onboarding');
		}
	}
</script>

<div class="flex flex-1 flex-col overflow-hidden">
<div class="flex-1 overflow-y-auto">
<div class="px-8 pb-4 pt-8">
	<p class="mb-1 text-[13px] font-semibold uppercase tracking-[0.05em] text-text-secondary">
		{m.nav_collective()}
	</p>
	<h1 class="text-[20px] font-semibold tracking-[-0.01em] text-slate-900 dark:text-slate-50">
		{m.manage_title()}
	</h1>
</div>
<div class="px-8 py-6">

	{#if error}
		<p class="mb-4 text-sm text-red-600">{error}</p>
	{/if}

	<!-- Collective identity (Fase 10.2) — admin only -->
	{#if isAdmin && $currentCollective}
		<section class="mb-8">
			<div class="relative flex items-center gap-3">
				<button
					type="button"
					data-testid="collective-emoji-toggle"
					onclick={() => (emojiPickerOpen = !emojiPickerOpen)}
					class="flex h-12 w-12 items-center justify-center rounded-lg bg-surface-container-low text-3xl
						hover:bg-black/5 dark:bg-surface-raised dark:hover:bg-white/5"
					aria-label={m.manage_collective_emoji_label()}
				>
					{$currentCollective.emoji}
				</button>
				<div class="flex-1">
					<label for="collective-name-edit" class="mb-1 block text-[13px] font-semibold uppercase tracking-[0.05em] text-text-secondary">
						{m.manage_collective_name_label()}
					</label>
					<div class="relative">
						<input
							id="collective-name-edit"
							data-testid="collective-name-edit"
							type="text"
							bind:value={nameDraft}
							onkeydown={onNameKeydown}
							onblur={() => void saveCollectiveName()}
							maxlength="60"
							class="w-full rounded-lg border border-slate-300 bg-surface px-3 py-2 text-sm
								focus:border-slate-500 focus:outline-none dark:border-slate-600 dark:bg-slate-800"
						/>
						{#if nameSaving}
							<span class="absolute right-3 top-2 text-xs text-text-secondary">{m.settings_saving()}</span>
						{:else if nameSaved}
							<span class="absolute right-3 top-2 text-xs text-emerald-600">✓</span>
						{/if}
					</div>
				</div>
				<button
					type="button"
					data-testid="collective-name-save"
					onclick={() => void saveCollectiveName()}
					class="self-end rounded-md bg-slate-900 px-3 py-2 text-xs font-semibold text-white hover:opacity-90
						dark:bg-slate-50 dark:text-slate-900"
				>
					{m.manage_collective_save()}
				</button>
			</div>
			{#if emojiPickerOpen}
				<div class="mt-3 grid grid-cols-8 gap-1 rounded-lg bg-surface-container-low p-3 dark:bg-surface-raised">
					{#each EMOJI_OPTIONS as e}
						<button
							type="button"
							data-testid="collective-emoji-option-{e}"
							class="flex h-9 w-9 items-center justify-center rounded-md text-xl transition-colors
								{$currentCollective.emoji === e
								? 'bg-slate-900 dark:bg-slate-100'
								: 'hover:bg-slate-100 dark:hover:bg-slate-700'}"
							onclick={() => void selectEmoji(e)}
							aria-label={e}
						>{e}</button>
					{/each}
				</div>
			{/if}
		</section>
	{/if}

	<!-- Members list — no dividers, vertical padding creates separation -->
	<section class="mb-8">
		<h2 class="mb-4 text-[13px] font-semibold uppercase tracking-[0.05em] text-text-secondary">
			{m.manage_members()}
		</h2>

		{#if loading}
			<p class="text-sm text-text-secondary">{m.loading()}</p>
		{:else}
			<ul>
				{#each members as member}
					<li data-testid="member-row-{member.user_id}" class="flex items-center gap-3 py-3">
						<Avatar
							name={member.display_name}
							type={member.avatar_type}
							emoji={member.avatar_emoji}
							src={member.avatar_url}
							size={36}
						/>
						<div class="min-w-0 flex-1">
							<p class="truncate text-sm font-medium text-slate-900 dark:text-slate-50">
								{member.display_name}
								{#if member.user_id === $currentUser?.id}
									<span class="ml-1 text-text-secondary">({m.manage_you()})</span>
								{/if}
							</p>
						</div>

						{#if isAdmin && member.user_id !== $currentUser?.id}
							<select
								data-testid="role-select-{member.user_id}"
								value={member.role}
								onchange={(e) => changeRole(member.user_id, e.currentTarget.value as Member['role'])}
								class="rounded-md border border-slate-300 bg-surface px-2 py-1 text-xs
									dark:border-slate-600 dark:bg-slate-800"
							>
								{#each ROLES as r}
									<option value={r}>{roleLabel(r)}</option>
								{/each}
							</select>
							<button
								data-testid="remove-member-{member.user_id}"
								onclick={() => removeMember(member.user_id)}
								class="rounded-md p-1.5 text-slate-400 hover:bg-red-50 hover:text-red-600
									dark:hover:bg-red-900/20"
								aria-label={m.manage_remove()}
							>✕</button>
						{:else}
							<span class="rounded-md bg-slate-100 px-2 py-1 text-xs text-slate-600
								dark:bg-slate-700 dark:text-slate-400">
								{roleLabel(member.role)}
							</span>
						{/if}
					</li>
				{/each}
			</ul>
		{/if}
	</section>

	<!-- Invite link generator — background shift instead of border -->
	{#if isAdmin}
		<section class="rounded-lg bg-surface-container-low p-4 dark:bg-surface-raised">
			<h2 class="mb-3 text-[13px] font-semibold uppercase tracking-[0.05em] text-text-secondary">
				{m.manage_invite_title()}
			</h2>

			<div class="mb-3 flex items-center gap-2">
				<label for="invite-role" class="text-sm text-slate-700 dark:text-slate-300">{m.manage_invite_role()}</label>
				<select
					id="invite-role"
					bind:value={inviteRole}
					class="rounded-md border border-slate-300 bg-surface px-2 py-1 text-sm
						dark:border-slate-600 dark:bg-slate-800"
				>
					<option value="member">{m.role_member()}</option>
					<option value="guest">{m.role_guest()}</option>
				</select>
			</div>

			<button
				data-testid="generate-invite"
				onclick={generateInviteLink}
				disabled={generating}
				class="mb-3 w-full rounded-lg bg-slate-900 px-4 py-2 text-sm font-semibold text-white
					hover:opacity-90 disabled:opacity-50 dark:bg-slate-50 dark:text-slate-900"
			>
				{generating ? m.loading() : m.manage_generate_link()}
			</button>

			{#if generatedLink}
				<div class="flex items-center gap-2 rounded-lg bg-surface p-2 dark:bg-surface-raised">
					<code data-testid="invite-link" class="min-w-0 flex-1 truncate text-xs text-slate-600 dark:text-slate-400">
						{generatedLink}
					</code>
					<button
						onclick={copyLink}
						class="flex-shrink-0 rounded-md px-2 py-1 text-xs font-medium text-slate-700
							hover:bg-slate-200 dark:text-slate-300 dark:hover:bg-slate-700"
					>
						{copied ? m.manage_copied() : m.manage_copy()}
					</button>
				</div>
				<p class="mt-1 text-xs text-text-secondary">{m.manage_link_expires()}</p>
			{/if}
		</section>

		<!-- Section visibility (Fase 12.4.2) — admin only. Collective-level
		     toggles are the higher precedence layer; turning one off hides
		     the section for every member. -->
		<section data-testid="manage-section-visibility" class="mt-6">
			<h2 class="mb-1 text-[13px] font-semibold uppercase tracking-[0.05em] text-text-secondary">
				{m.collective_section_visibility_title()}
			</h2>
			<p class="mb-3 text-xs text-text-secondary">
				{m.collective_section_visibility_blurb()}
			</p>
			<ul class="space-y-1">
				{#each SECTION_KEYS as section (section)}
					{@const enabled = collectiveFlag(section)}
					<li class="flex items-center justify-between gap-3 rounded-md bg-surface-raised px-3 py-2">
						<p class="min-w-0 flex-1 text-sm text-slate-900 dark:text-slate-50">{sectionLabel(section)}</p>
						<label class="inline-flex shrink-0 cursor-pointer items-center">
							<input
								type="checkbox"
								data-testid="manage-section-toggle-{section}"
								checked={enabled}
								onchange={() => void toggleCollectiveSection(section)}
								class="h-4 w-4 cursor-pointer accent-slate-900 dark:accent-slate-50"
							/>
						</label>
					</li>
				{/each}
			</ul>
		</section>

		<!-- Danger zone (Fase 10.3) — admin only -->
		<section class="mt-10 rounded-lg border border-destructive/40 p-4">
			<h2 class="mb-2 text-[13px] font-semibold uppercase tracking-[0.05em] text-destructive">
				{m.manage_dissolve_section()}
			</h2>
			<p class="mb-3 text-sm text-text-secondary">{m.manage_dissolve_blurb()}</p>
			<button
				type="button"
				data-testid="dissolve-collective-button"
				onclick={() => void openDissolve()}
				class="rounded-md border border-destructive px-4 py-2 text-sm font-semibold text-destructive
					hover:bg-destructive/10"
			>
				{m.manage_dissolve_button()}
			</button>
		</section>
	{/if}
</div>
</div>
</div>

{#if dissolveOpen && $currentCollective}
	<div class="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4" data-testid="dissolve-modal">
		<div class="w-full max-w-md rounded-lg bg-surface p-5 shadow-[0px_20px_40px_rgba(15,23,42,0.2)] dark:bg-surface-raised">
			<h2 class="mb-2 text-base font-semibold text-slate-900 dark:text-slate-50">
				{m.manage_dissolve_title({ name: $currentCollective.name })}
			</h2>
			<p class="mb-4 text-sm text-text-secondary">
				{m.manage_dissolve_warning({ lists: listsCount, tasks: tasksCount, notes: notesCount })}
			</p>
			<label for="dissolve-confirm-input" class="mb-1 block text-xs font-medium text-text-secondary">
				{m.manage_dissolve_confirm_label({ name: $currentCollective.name })}
			</label>
			<input
				id="dissolve-confirm-input"
				data-testid="dissolve-confirm-input"
				type="text"
				bind:value={dissolveConfirmInput}
				class="mb-3 w-full rounded-lg border border-slate-300 bg-surface px-3 py-2 text-sm
					focus:border-slate-500 focus:outline-none dark:border-slate-600 dark:bg-slate-800"
			/>
			{#if dissolveError}
				<p class="mb-3 text-sm text-destructive" data-testid="dissolve-error">{dissolveError}</p>
			{/if}
			<div class="flex justify-end gap-2">
				<button
					type="button"
					onclick={closeDissolve}
					class="rounded-md px-3 py-1.5 text-sm font-medium text-slate-600 hover:bg-slate-100 dark:text-slate-300 dark:hover:bg-slate-800"
				>
					{m.common_cancel()}
				</button>
				<button
					type="button"
					data-testid="dissolve-confirm-button"
					disabled={!dissolveConfirmReady || dissolveInFlight}
					onclick={() => void confirmDissolve()}
					class="rounded-md bg-destructive px-4 py-1.5 text-sm font-semibold text-white hover:opacity-90 disabled:opacity-50"
				>
					{m.manage_dissolve_confirm_button()}
				</button>
			</div>
		</div>
	</div>
{/if}
