<script lang="ts">
	import { Shield, Plus, Trash2, ChevronRight, ChevronDown } from '@lucide/svelte';
	import * as Card from '$lib/components/ui/card';
	import { Button } from '$lib/components/ui/button';
	import { toast } from 'svelte-sonner';
	import { companyStore } from '$lib/stores/company.svelte';
	import { rolesAPI, type CompanyRole } from '$lib/api/dashboard/admin/roles';
	import { permissionsAPI, type Permission } from '$lib/api/dashboard/admin/permissions';
	import { rolePermissionsAPI } from '$lib/api/dashboard/admin/role-permissions';

	const inputCls =
		'rounded-md border bg-transparent px-3 py-2 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring';

	const companyId = $derived(companyStore.activeCompany?.id ?? null);

	let roles = $state<CompanyRole[]>([]);
	let catalog = $state<Permission[]>([]);
	let loading = $state(true);
	let creating = $state(false);
	let name = $state('');
	let code = $state('');
	let description = $state('');
	let expandedRoleId = $state<number | null>(null);
	// roleId → Set de permission_id asignados
	let rolePerms = $state<Record<number, Set<number>>>({});
	let savingPerm = $state<string | null>(null);

	// Catálogo agrupado por módulo
	const byModule = $derived.by(() => {
		const m: Record<string, Permission[]> = {};
		for (const p of catalog) (m[p.module] ??= []).push(p);
		return m;
	});

	function slugify(s: string): string {
		return s.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
	}

	async function load() {
		if (!companyId) {
			loading = false;
			return;
		}
		loading = true;
		try {
			const [rRes, pRes] = await Promise.all([
				rolesAPI.list(companyId, { page_size: 100 }),
				permissionsAPI.list({ page_size: 1000 })
			]);
			roles = rRes.data?.items ?? [];
			catalog = pRes.items ?? [];
		} catch {
			toast.error('No se pudieron cargar roles/permisos');
		} finally {
			loading = false;
		}
	}

	// Recarga los roles cuando cambia la compañía activa —incluida la hidratación
	// inicial tras refrescar (en onMount el store aún no tenía compañía, por eso
	// antes no aparecían hasta re-seleccionarla).
	$effect(() => {
		const id = companyId;
		expandedRoleId = null;
		rolePerms = {};
		if (id) {
			void load();
		} else {
			roles = [];
			loading = false;
		}
	});

	async function createRole() {
		if (!companyId) return;
		const n = name.trim();
		if (n.length < 2) {
			toast.error('El nombre del rol es obligatorio');
			return;
		}
		const c = (code.trim() || slugify(n));
		creating = true;
		try {
			const res = await rolesAPI.create(companyId, { name: n, code: c, description: description.trim() || undefined });
			if (res.error) {
				toast.error(res.error);
				return;
			}
			toast.success('Rol creado');
			name = '';
			code = '';
			description = '';
			await load();
		} finally {
			creating = false;
		}
	}

	async function delRole(r: CompanyRole) {
		if (!companyId) return;
		if (!confirm(`¿Eliminar el rol "${r.name}"?`)) return;
		const res = await rolesAPI.delete(r.id, companyId);
		if (res.error) {
			toast.error(res.error);
			return;
		}
		toast.success('Rol eliminado');
		await load();
	}

	async function toggleExpand(r: CompanyRole) {
		if (expandedRoleId === r.id) {
			expandedRoleId = null;
			return;
		}
		expandedRoleId = r.id;
		if (!rolePerms[r.id] && companyId) {
			try {
				const resp = await rolePermissionsAPI.listByRole(r.id, companyId);
				rolePerms = { ...rolePerms, [r.id]: new Set((resp.permissions ?? []).map((p) => p.permission_id)) };
			} catch {
				rolePerms = { ...rolePerms, [r.id]: new Set() };
			}
		}
	}

	async function togglePerm(roleId: number, perm: Permission, checked: boolean) {
		if (!companyId) return;
		savingPerm = `${roleId}:${perm.id}`;
		try {
			if (checked) {
				await rolePermissionsAPI.assign(roleId, companyId, { permission_id: perm.id });
				rolePerms[roleId]?.add(perm.id);
			} else {
				await rolePermissionsAPI.remove(roleId, perm.id, companyId);
				rolePerms[roleId]?.delete(perm.id);
			}
			rolePerms = { ...rolePerms };
			toast.success(checked ? 'Permiso agregado' : 'Permiso quitado');
		} catch (e) {
			toast.error('No se pudo actualizar el permiso');
		} finally {
			savingPerm = null;
		}
	}
</script>

<div class="space-y-6">
	<div>
		<h1 class="flex items-center gap-2 text-2xl font-bold tracking-tight">
			<Shield class="h-6 w-6" /> Roles y permisos
		</h1>
		<p class="mt-1 text-sm text-muted-foreground">
			Define roles (carriles) por compañía y qué puede hacer cada uno. Los usuarios se asignan en Usuarios.
		</p>
	</div>

	{#if !companyId}
		<Card.Root><Card.Content class="pt-6 text-sm text-muted-foreground">Selecciona una compañía activa para gestionar sus roles.</Card.Content></Card.Root>
	{:else}
		<Card.Root>
			<Card.Header>
				<Card.Title class="flex items-center gap-2"><Plus class="h-4 w-4" /> Nuevo rol</Card.Title>
			</Card.Header>
			<Card.Content>
				<div class="grid gap-4 sm:grid-cols-3">
					<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Nombre *</span><input class={inputCls} bind:value={name} placeholder="Ventas" /></label>
					<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Código</span><input class="font-mono {inputCls}" bind:value={code} placeholder="(auto)" title="Se genera del nombre si lo dejas vacío" /></label>
					<label class="flex flex-col gap-1 text-sm"><span class="font-medium">Descripción</span><input class={inputCls} bind:value={description} /></label>
				</div>
				<div class="mt-4 flex justify-end"><Button onclick={createRole} disabled={creating}>{creating ? 'Creando…' : 'Crear rol'}</Button></div>
			</Card.Content>
		</Card.Root>

		<Card.Root>
			<Card.Header>
				<Card.Title>Roles ({roles.length})</Card.Title>
				<Card.Description>Haz clic en un rol para ver y editar sus permisos.</Card.Description>
			</Card.Header>
			<Card.Content class="space-y-2">
				{#if loading}
					<p class="text-sm text-muted-foreground">Cargando…</p>
				{:else if roles.length === 0}
					<p class="text-sm text-muted-foreground">No hay roles. Crea uno arriba.</p>
				{:else}
					{#each roles as r (r.id)}
						<div class="rounded-md border">
							<div class="flex items-center gap-2 px-3 py-2">
								<button type="button" class="flex flex-1 items-center gap-2 text-left" onclick={() => toggleExpand(r)}>
									{#if expandedRoleId === r.id}<ChevronDown class="h-4 w-4" />{:else}<ChevronRight class="h-4 w-4" />{/if}
									<span class="font-medium">{r.name}</span>
									<span class="font-mono text-xs text-muted-foreground">{r.code}</span>
								</button>
								<Button variant="ghost" size="sm" onclick={() => delRole(r)}><Trash2 class="h-4 w-4 text-destructive" /></Button>
							</div>
							{#if expandedRoleId === r.id}
								<div class="border-t p-3">
									{#if !rolePerms[r.id]}
										<p class="text-sm text-muted-foreground">Cargando permisos…</p>
									{:else}
										<div class="space-y-4">
											{#each Object.entries(byModule) as [mod, perms] (mod)}
												<div>
													<p class="mb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">{mod}</p>
													<div class="grid gap-1 sm:grid-cols-2 lg:grid-cols-3">
														{#each perms as p (p.id)}
															<label class="flex items-center gap-2 text-sm">
																<input
																	type="checkbox"
																	class="h-4 w-4 rounded border"
																	checked={rolePerms[r.id].has(p.id)}
																	disabled={savingPerm === `${r.id}:${p.id}`}
																	onchange={(e) => togglePerm(r.id, p, (e.currentTarget as HTMLInputElement).checked)}
																/>
																<span title={p.code}>{p.description || p.code}</span>
															</label>
														{/each}
													</div>
												</div>
											{/each}
										</div>
									{/if}
								</div>
							{/if}
						</div>
					{/each}
				{/if}
			</Card.Content>
		</Card.Root>
	{/if}
</div>
