<script lang="ts">
	import { useQuery, useConvexClient } from 'convex-svelte';
	import { api } from '@sgse-app/backend/convex/_generated/api';
	import ProtectedRoute from '$lib/components/ProtectedRoute.svelte';
	import { goto } from '$app/navigation';
	import { resolve } from '$app/paths';
	import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
	import {
		Home,
		ShieldCheck,
		Plus,
		ArrowLeft,
		CheckCircle,
		XCircle,
		Search,
		X,
		ChevronDown
	} from 'lucide-svelte';

	const client = useConvexClient();

	// Carregar lista de roles e catálogo de recursos/ações
	const rolesQuery = useQuery(api.roles.listar, {});
	const catalogoQuery = useQuery(api.permissoesAcoes.listarRecursosEAcoes, {});

	let salvando = $state(false);
	let mensagem = $state<{ tipo: 'success' | 'error'; texto: string } | null>(null);
	let busca = $state('');
	let filtroRole = $state<Id<'roles'> | ''>('');
	let modalNovoPerfilAberto = $state(false);
	let nomeNovoPerfil = $state('');
	let descricaoNovoPerfil = $state('');
	let setorNovoPerfil = $state('');
	let nivelNovoPerfil = $state(3);
	let roleParaDuplicar = $state<Id<'roles'> | ''>('');
	let criandoNovoPerfil = $state(false);

	// Controla quais recursos estão expandidos (mostrando as ações) por perfil
	// Formato: { "roleId-recurso": true/false }
	let recursosExpandidos: Record<string, boolean> = $state({});

	// Cache de permissões por role
	let permissoesPorRole: Record<string, Array<{ recurso: string; acoes: Array<string> }>> = $state(
		{}
	);

	async function carregarPermissoesRole(roleId: Id<'roles'>) {
		if (permissoesPorRole[roleId]) return;
		const dados = await client.query(api.permissoesAcoes.listarPermissoesAcoesPorRole, { roleId });
		permissoesPorRole[roleId] = dados;
	}

	function toggleRecurso(roleId: Id<'roles'>, recurso: string) {
		const key = `${roleId}-${recurso}`;
		recursosExpandidos[key] = !recursosExpandidos[key];
	}

	function isRecursoExpandido(roleId: Id<'roles'>, recurso: string) {
		const key = `${roleId}-${recurso}`;
		return recursosExpandidos[key] ?? false;
	}

	function mostrarMensagem(tipo: 'success' | 'error', texto: string) {
		mensagem = { tipo, texto };
		setTimeout(() => {
			mensagem = null;
		}, 3000);
	}

	const rolesFiltradas = $derived.by(() => {
		if (!rolesQuery.data) return [];
		let rs = rolesQuery.data; // Removed explicit type annotation
		if (filtroRole) rs = rs.filter((r) => r._id === filtroRole); // Removed as any
		if (busca.trim()) {
			const b = busca.toLowerCase();
			rs = rs.filter(
				(r) => r.descricao.toLowerCase().includes(b) || r.nome.toLowerCase().includes(b)
			);
		}
		return rs;
	});

	// Carregar permissões para todos os perfis filtrados quando necessário
	$effect(() => {
		if (rolesFiltradas && catalogoQuery.data) {
			for (const roleRow of rolesFiltradas) {
				if (roleRow.nivel > 1) {
					carregarPermissoesRole(roleRow._id);
				}
			}
		}
	});

	async function toggleAcao(roleId: Id<'roles'>, recurso: string, acao: string, conceder: boolean) {
		try {
			salvando = true;
			await client.mutation(api.permissoesAcoes.atualizarPermissaoAcao, {
				roleId,
				recurso,
				acao,
				conceder
			});
			// Atualizar cache local
			const atual = permissoesPorRole[roleId] || [];
			const entry = atual.find((e) => e.recurso === recurso);
			if (entry) {
				entry.acoes = conceder
					? [...entry.acoes.filter((valor) => valor !== acao), acao]
					: entry.acoes.filter((valor) => valor !== acao);
			} else if (conceder) {
				permissoesPorRole[roleId] = [...atual, { recurso, acoes: [acao] }];
			}
			mostrarMensagem('success', 'Permissão atualizada com sucesso!');
		} catch (error: unknown) {
			// Changed to unknown
			const message = error instanceof Error ? error.message : 'Erro ao atualizar permissão';
			mostrarMensagem('error', message);
		} finally {
			salvando = false;
		}
	}

	function isConcedida(roleId: Id<'roles'>, recurso: string, acao: string) {
		const dados = permissoesPorRole[roleId];
		const entry = dados?.find((e) => e.recurso === recurso);
		return entry ? entry.acoes.includes(acao) : false;
	}

	const gerarIdentificador = (valor: string) =>
		valor
			.normalize('NFD')
			.replace(/[\u0300-\u036f]/g, '')
			.trim()
			.toLowerCase()
			.replace(/[^a-z0-9]+/g, '_')
			.replace(/^_+|_+$/g, '')
			.replace(/_{2,}/g, '_');

	const identificadorSugerido = $derived.by(() => gerarIdentificador(nomeNovoPerfil));

	const podeSalvarNovoPerfil = $derived.by(() => {
		const nome = nomeNovoPerfil.trim();
		const nivel = Number(nivelNovoPerfil);
		const nivelValido = Number.isFinite(nivel) && nivel >= 0 && nivel <= 10;
		return nome.length >= 3 && nivelValido && !criandoNovoPerfil;
	});

	const roleDuplicacaoSelecionada = $derived.by(() => {
		if (!roleParaDuplicar || !rolesQuery.data) return null;
		return rolesQuery.data.find((role) => role._id === roleParaDuplicar) ?? null;
	});

	$effect(() => {
		if (roleParaDuplicar) {
			carregarPermissoesRole(roleParaDuplicar);
		}
	});

	const resumoPermissoesDuplicacao = $derived.by(() => {
		if (!roleParaDuplicar) return null;
		const permissoes = permissoesPorRole[roleParaDuplicar];
		if (!permissoes) return null;
		const totalRecursos = permissoes.length;
		const totalAcoes = permissoes.reduce((acc, item) => acc + item.acoes.length, 0);
		return { totalRecursos, totalAcoes };
	});

	function abrirModalNovoPerfil() {
		nomeNovoPerfil = '';
		descricaoNovoPerfil = '';
		setorNovoPerfil = '';
		nivelNovoPerfil = 3;
		roleParaDuplicar = '';
		modalNovoPerfilAberto = true;
	}

	function fecharModalNovoPerfil() {
		modalNovoPerfilAberto = false;
	}

	async function criarNovoPerfil() {
		if (!podeSalvarNovoPerfil) return;

		const nome = nomeNovoPerfil.trim();
		const descricao = descricaoNovoPerfil.trim();
		const setor = setorNovoPerfil.trim();
		const nivel = Math.min(Math.max(Math.round(Number(nivelNovoPerfil)), 0), 10);

		criandoNovoPerfil = true;
		try {
			const resultado = await client.mutation(api.roles.criar, {
				nome,
				descricao,
				nivel,
				setor: setor.length > 0 ? setor : undefined,
				copiarDeRoleId: roleParaDuplicar || undefined
			});

			if (resultado.sucesso) {
				mostrarMensagem('success', 'Perfil criado com sucesso!');
				modalNovoPerfilAberto = false;
			} else {
				const mapaErros: Record<string, string> = {
					nome_ja_utilizado:
						'Já existe um perfil com este identificador. Ajuste o nome e tente novamente.',
					nome_invalido: 'Informe um nome válido com pelo menos 3 caracteres.',
					sem_permissao: 'Você não possui permissão para criar novos perfis.',
					role_origem_nao_encontrada: 'Não foi possível carregar o perfil escolhido como base.'
				};
				const mensagemErro =
					mapaErros[resultado.erro] ?? 'Não foi possível criar o perfil. Tente novamente.';
				mostrarMensagem('error', mensagemErro);
			}
		} catch (error: unknown) {
			const mensagemErro =
				error instanceof Error ? error.message : 'Erro inesperado ao criar o perfil.';
			mostrarMensagem('error', mensagemErro);
		} finally {
			criandoNovoPerfil = false;
		}
	}
</script>

<ProtectedRoute allowedRoles={['ti_master', 'admin']} maxLevel={1}>
	<!-- Breadcrumb -->
	<div class="breadcrumbs mb-4 text-sm">
		<ul>
			<li>
				<a href={resolve('/')} class="text-primary hover:text-primary-focus">
					<Home class="h-4 w-4" strokeWidth={2} />
					Dashboard
				</a>
			</li>
			<li>
				<a href={resolve('/ti')} class="text-primary hover:text-primary-focus">TI</a>
			</li>
			<li class="font-semibold">Gerenciar Perfis & Permissões</li>
		</ul>
	</div>

	<!-- Header -->
	<div class="mb-6">
		<div class="mb-2 flex flex-wrap items-center gap-3">
			<div class="bg-primary/10 rounded-xl p-3">
				<ShieldCheck class="text-primary h-8 w-8" strokeWidth={2} />
			</div>
			<div class="flex-1">
				<h1 class="text-base-content text-3xl font-bold">
					Gerenciar Perfis & Permissões de Acesso
				</h1>
				<p class="text-base-content/60 mt-1">
					Configure as permissões de acesso aos menus do sistema por função
				</p>
			</div>
			<button class="btn btn-primary gap-2" onclick={abrirModalNovoPerfil}>
				<Plus class="h-5 w-5" strokeWidth={2} />
				Criar novo perfil
			</button>
			<button class="btn gap-2" onclick={() => goto(resolve('/ti'))}>
				<ArrowLeft class="h-5 w-5" strokeWidth={2} />
				Voltar
			</button>
		</div>
	</div>

	<!-- Alertas -->
	{#if mensagem}
		<div
			class="alert mb-6 shadow-lg"
			class:alert-success={mensagem.tipo === 'success'}
			class:alert-error={mensagem.tipo === 'error'}
		>
			{#if mensagem.tipo === 'success'}
				<CheckCircle class="h-6 w-6 shrink-0 stroke-current" strokeWidth={2} />
			{:else}
				<XCircle class="h-6 w-6 shrink-0 stroke-current" strokeWidth={2} />
			{/if}
			<span class="font-semibold">{mensagem.texto}</span>
		</div>
	{/if}

	<!-- Filtros e Busca -->
	<div class="card bg-base-100 mb-6 shadow-xl">
		<div class="card-body">
			<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
				<!-- Busca por menu -->
				<div class="form-control">
					<label class="label" for="busca">
						<span class="label-text font-semibold">Buscar Perfil</span>
					</label>
					<div class="relative">
						<input
							id="busca"
							type="text"
							placeholder="Digite o nome/descrição do perfil..."
							class="input input-bordered w-full pr-10"
							bind:value={busca}
						/>
						<Search class="text-base-content/40 absolute top-3.5 right-3 h-5 w-5" strokeWidth={2} />
					</div>
				</div>

				<!-- Filtro por perfil -->
				<div class="form-control">
					<label class="label" for="filtroRole">
						<span class="label-text font-semibold">Filtrar por Perfil</span>
					</label>
					<select id="filtroRole" class="select select-bordered w-full" bind:value={filtroRole}>
						<option value="">Todos os perfis</option>
						{#if rolesQuery.data}
							{#each rolesQuery.data as roleRow (roleRow._id)}
								<option value={roleRow._id}>
									{roleRow.descricao} ({roleRow.nome})
								</option>
							{/each}
						{/if}
					</select>
				</div>
			</div>

			{#if busca || filtroRole}
				<div class="mt-2 flex items-center gap-2">
					<span class="text-base-content/60 text-sm">Filtros ativos:</span>
					{#if busca}
						<div class="badge badge-primary gap-2">
							Busca: {busca}
							<button class="btn btn-xs" onclick={() => (busca = '')} aria-label="Limpar busca">
								✕
							</button>
						</div>
					{/if}
					{#if filtroRole}
						<div class="badge badge-secondary gap-2">
							Perfil filtrado
							<button
								class="btn btn-xs"
								onclick={() => (filtroRole = '')}
								aria-label="Limpar filtro"
							>
								✕
							</button>
						</div>
					{/if}
				</div>
			{/if}
		</div>
	</div>

	<!-- Matriz de Permissões por Ação -->
	{#if rolesQuery.isLoading || catalogoQuery.isLoading}
		<div class="flex items-center justify-center py-12">
			<span class="loading loading-spinner loading-lg text-primary"></span>
		</div>
	{:else if rolesQuery.error}
		<div class="alert alert-error">
			<XCircle class="h-6 w-6 shrink-0 stroke-current" strokeWidth={2} />
			<span>Erro ao carregar perfis: {rolesQuery.error.message}</span>
		</div>
	{:else if rolesQuery.data && catalogoQuery.data}
		{#if rolesFiltradas.length === 0}
			<div class="card bg-base-100 shadow-xl">
				<div class="card-body items-center text-center">
					<Search class="text-base-content/30 h-16 w-16" strokeWidth={2} />
					<h3 class="mt-4 text-xl font-bold">Nenhum resultado encontrado</h3>
					<p class="text-base-content/60">
						{busca
							? `Não foram encontrados perfis com "${busca}"`
							: 'Nenhum perfil corresponde aos filtros aplicados'}
					</p>
					<button
						class="btn btn-primary btn-sm mt-4"
						onclick={() => {
							busca = '';
							filtroRole = '';
						}}
					>
						Limpar Filtros
					</button>
				</div>
			</div>
		{/if}

		{#each rolesFiltradas as roleRow (roleRow._id)}
			{@const roleId = roleRow._id}
			<div class="card bg-base-100 mb-6 shadow-xl">
				<div class="card-body">
					<div class="mb-4 flex flex-wrap items-center gap-4">
						<div class="min-w-[200px] flex-1">
							<div class="mb-2 flex items-center gap-3">
								<h2 class="card-title text-2xl">{roleRow.descricao}</h2>
								<div class="badge badge-lg badge-primary">
									Nível {roleRow.nivel}
								</div>
								{#if roleRow.nivel <= 1}
									<div class="badge badge-lg badge-success gap-1">
										<CheckCircle class="h-4 w-4" strokeWidth={2} />
										Acesso Total
									</div>
								{/if}
							</div>
							<p class="text-base-content/60 text-sm">
								<span class="bg-base-200 rounded px-2 py-1 font-mono">{roleRow.nome}</span>
							</p>
						</div>
					</div>

					{#if roleRow.nivel <= 1}
						<div class="alert alert-success shadow-md">
							<CheckCircle class="h-6 w-6 shrink-0 stroke-current" strokeWidth={2} />
							<div>
								<h3 class="font-bold">Perfil Administrativo</h3>
								<div class="text-sm">
									Este perfil possui acesso total ao sistema automaticamente, sem necessidade de
									configuração manual.
								</div>
							</div>
						</div>
					{:else if catalogoQuery.data && catalogoQuery.data.length > 0}
						<div class="space-y-2">
							{#each catalogoQuery.data as item (item.recurso)}
								{@const recursoExpandido = isRecursoExpandido(roleId, item.recurso)}
								<div class="border-base-300 overflow-hidden rounded-lg border">
									<!-- Cabeçalho do recurso (clicável) -->
									<button
										type="button"
										class="bg-base-200 hover:bg-base-300 flex w-full items-center justify-between px-4 py-3 transition-colors"
										onclick={() => toggleRecurso(roleId, item.recurso)}
										disabled={salvando}
									>
										<span class="text-lg font-semibold">{item.recurso}</span>
										<ChevronDown
										class="h-5 w-5 transition-transform {recursoExpandido ? 'rotate-180' : ''}"
											strokeWidth={2}
										/>
									</button>

									<!-- Lista de ações (visível quando expandido) -->
									{#if recursoExpandido}
										<div class="bg-base-100 border-base-300 border-t px-4 py-3">
											{#if item.acoes.length === 0}
												<p class="text-base-content/60 text-sm">
													Nenhuma permissão cadastrada para este recurso.
												</p>
											{:else}
												<div class="space-y-2">
													{#each item.acoes as acao (acao)}
														<label
															class="hover:bg-base-200 flex cursor-pointer items-center gap-3 rounded p-2 transition-colors"
														>
															<input
																type="checkbox"
																class="checkbox checkbox-primary"
																checked={isConcedida(roleId, item.recurso, acao)}
																disabled={salvando}
																onchange={(e) =>
																	toggleAcao(roleId, item.recurso, acao, e.currentTarget.checked)}
															/>
															<span class="flex-1 font-medium">{acao}</span>
														</label>
													{/each}
												</div>
											{/if}
										</div>
									{/if}
								</div>
							{/each}
						</div>
					{:else}
						<div class="alert alert-info mt-4">
							<span class="font-semibold">
								Nenhuma permissão cadastrada ainda. Use o botão “Criar permissão” para começar.
							</span>
						</div>
					{/if}
				</div>
			</div>
		{/each}
	{/if}

	{#if modalNovoPerfilAberto}
		<dialog class="modal modal-open">
			<div
				class="modal-box bg-base-100 w-full max-w-4xl overflow-hidden rounded-2xl p-0 shadow-2xl"
			>
				<div
					class="from-primary via-primary/85 to-secondary/80 text-base-100 relative bg-linear-to-r px-8 py-6"
				>
					<button
						type="button"
						class="btn btn-circle btn-ghost btn-sm text-base-100/80 hover:text-base-100 absolute top-4 right-4"
						onclick={fecharModalNovoPerfil}
						aria-label="Fechar"
					>
						✕
					</button>
					<div class="space-y-2 pr-10">
						<h3 class="text-3xl font-black tracking-tight">Criar novo perfil de acesso</h3>
						<p class="text-base-100/80 max-w-2xl text-sm md:text-base">
							Defina as informações do perfil e, se desejar, reutilize as permissões de um perfil
							existente para acelerar a configuração.
						</p>
						{#if identificadorSugerido}
							<div class="text-base-100/80 flex flex-wrap items-center gap-2 text-xs">
								<span
									class="badge badge-outline badge-sm border-base-100/40 tracking-widest uppercase"
								>
									Identificador
								</span>
								<span class="font-mono text-sm">{identificadorSugerido}</span>
							</div>
						{/if}
					</div>
				</div>
				<div class="space-y-6 px-8 py-6">
					<div class="grid gap-6 md:grid-cols-2">
						<div class="form-control md:col-span-2">
							<label class="label" for="nome-novo-perfil">
								<span class="label-text font-semibold">Nome do perfil *</span>
							</label>
							<input
								id="nome-novo-perfil"
								type="text"
								class="input input-bordered input-primary"
								placeholder="Ex.: Financeiro, RH, Supervisão de Campo"
								bind:value={nomeNovoPerfil}
								maxlength={60}
							/>
						</div>

						<div class="form-control md:col-span-2">
							<label class="label" for="descricao-novo-perfil">
								<span class="label-text font-semibold">Descrição</span>
							</label>
							<textarea
								id="descricao-novo-perfil"
								class="textarea textarea-bordered textarea-primary min-h-[96px]"
								placeholder="Explique como este perfil será utilizado e quais áreas ele atende."
								bind:value={descricaoNovoPerfil}
								maxlength={240}
							></textarea>
						</div>

						<div class="form-control">
							<label class="label" for="setor-novo-perfil">
								<span class="label-text font-semibold">Setor (opcional)</span>
							</label>
							<input
								id="setor-novo-perfil"
								type="text"
								class="input input-bordered"
								placeholder="Informe o setor ou departamento responsável"
								bind:value={setorNovoPerfil}
								maxlength={40}
							/>
						</div>

						<div class="form-control">
							<label class="label" for="nivel-novo-perfil">
								<span class="label-text font-semibold">Nível de acesso (0 a 10)</span>
							</label>
							<input
								id="nivel-novo-perfil"
								type="number"
								class="input input-bordered"
								min={0}
								max={10}
								step={1}
								bind:value={nivelNovoPerfil}
							/>
							<span class="text-base-content/60 mt-1 text-xs">
								Níveis menores representam maior privilégio (ex.: 0 = administrativo).
							</span>
						</div>

						<div class="form-control md:col-span-2">
							<label class="label" for="duplicar-novo-perfil">
								<span class="label-text font-semibold">Duplicar permissões de</span>
							</label>
							<select
								id="duplicar-novo-perfil"
								class="select select-bordered"
								bind:value={roleParaDuplicar}
							>
								<option value="">Iniciar perfil vazio</option>
								{#if rolesQuery.data}
									{#each rolesQuery.data as roleDuplicavel (roleDuplicavel._id)}
										<option value={roleDuplicavel._id}>
											{roleDuplicavel.descricao} — nível {roleDuplicavel.nivel}
										</option>
									{/each}
								{/if}
							</select>
						</div>
					</div>

					{#if roleDuplicacaoSelecionada}
						<div class="border-base-200 bg-base-100/80 rounded-2xl border p-4">
							<div class="flex flex-wrap items-center justify-between gap-4">
								<div>
									<p class="text-base-content font-semibold">
										Permissões a serem copiadas de <span class="font-bold"
											>{roleDuplicacaoSelecionada.descricao}</span
										>
									</p>
									<p class="text-base-content/70 text-sm">
										As permissões atuais serão reaproveitadas automaticamente para o novo perfil.
									</p>
								</div>
								{#if resumoPermissoesDuplicacao}
									<div class="flex items-center gap-4 text-sm">
										<span class="badge badge-outline badge-sm">
											{resumoPermissoesDuplicacao.totalRecursos} recursos
										</span>
										<span class="badge badge-outline badge-sm">
											{resumoPermissoesDuplicacao.totalAcoes} ações
										</span>
									</div>
								{:else}
									<span class="loading loading-dots loading-sm text-primary"></span>
								{/if}
							</div>
						</div>
					{/if}

					<div class="flex flex-col-reverse gap-3 sm:flex-row sm:items-center sm:justify-between">
						<p class="text-base-content/60 text-xs">
							Campos marcados com * são obrigatórios. As alterações entram em vigor imediatamente
							após a criação.
						</p>
						<div class="flex flex-wrap gap-3">
							<button
								type="button"
								class="btn"
								onclick={fecharModalNovoPerfil}
								disabled={criandoNovoPerfil}
							>
								Cancelar
							</button>
							<button
								type="button"
								class="btn btn-primary"
								disabled={!podeSalvarNovoPerfil}
								onclick={criarNovoPerfil}
							>
								{#if criandoNovoPerfil}
									<span class="loading loading-spinner"></span>
									Criando perfil...
								{:else}
									Salvar perfil
								{/if}
							</button>
						</div>
					</div>
				</div>
			</div>
			<form method="dialog" class="modal-backdrop">
				<button type="button" onclick={fecharModalNovoPerfil} aria-label="Fechar modal">
					fechar
				</button>
			</form>
		</dialog>
	{/if}
</ProtectedRoute>
