<script lang="ts">
	import Pencil from '@lucide/svelte/icons/pencil';
	import Trash2 from '@lucide/svelte/icons/trash-2';
	import Building2 from '@lucide/svelte/icons/building-2';
	import Plus from '@lucide/svelte/icons/plus';
	import { api } from '$lib/api/client';
	import { apiErrorCode, errorMessage } from '$lib/api/errors';
	import type { components } from '$lib/api/schema';
	import IconAction from '$lib/components/IconAction.svelte';
	import Button from '$lib/components/Button.svelte';
	import Card from '$lib/components/Card.svelte';
	import ConfirmDialog from '$lib/components/ConfirmDialog.svelte';
	import Dialog from '$lib/components/Dialog.svelte';
	import FormField from '$lib/components/FormField.svelte';
	import Input from '$lib/components/Input.svelte';
	import { m } from '$lib/paraglide/messages';

	type Department = components['schemas']['DepartmentOut'];

	// The page owns the list because the user manager reads it too; every
	// change here reports back so both stay on the same set.
	let {
		departments,
		onChanged
	}: { departments: Department[]; onChanged: () => Promise<void> | void } = $props();

	let error = $state<string | null>(null);
	let creating = $state(false);
	let editing = $state<Department | null>(null);
	let draft = $state('');
	let confirmRequest = $state<{ title: string; message: string; run: () => void } | null>(null);

	function startCreate() {
		error = null;
		draft = '';
		creating = true;
	}

	function startEdit(department: Department) {
		error = null;
		draft = department.name;
		editing = department;
	}

	async function create(event: SubmitEvent) {
		event.preventDefault();
		error = null;
		const { data, error: apiError } = await api.POST('/api/admin/departments', {
			body: { name: draft }
		});
		if (!data) {
			error = errorMessage(apiErrorCode(apiError), m.admin_departments_create_failed());
			return;
		}
		creating = false;
		await onChanged();
	}

	async function save(department: Department) {
		error = null;
		const { error: apiError } = await api.PATCH('/api/admin/departments/{department_id}', {
			params: { path: { department_id: department.id } },
			body: { name: draft }
		});
		if (apiError) {
			error = errorMessage(apiErrorCode(apiError), m.admin_departments_rename_failed());
			return;
		}
		editing = null;
		await onChanged();
	}

	function remove(department: Department) {
		confirmRequest = {
			title: m.common_delete(),
			message: m.admin_departments_delete_confirm({ name: department.name }),
			run: async () => {
				// The modal is the admin's acknowledgement, so pass confirm — the
				// backend otherwise refuses to silently drop a department still in
				// use (its shared-access grants CASCADE away).
				await api.DELETE('/api/admin/departments/{department_id}', {
					params: { path: { department_id: department.id }, query: { confirm: true } }
				});
				await onChanged();
			}
		};
	}
</script>

<Card>
	<div class="mb-3 flex flex-wrap items-center justify-between gap-2">
		<h2 class="flex items-center gap-2 text-lg font-semibold">
			<Building2 size={18} class="text-ink-muted" />
			{m.admin_departments_title()}
		</h2>
		<Button size="sm" onclick={startCreate} data-testid="new-department">
			<Plus size={15} />
			{m.admin_departments_new_button()}
		</Button>
	</div>

	{#if error && !creating && !editing}
		<p role="alert" class="mb-2 text-sm text-danger">{error}</p>
	{/if}

	<ul class="flex flex-col gap-1" data-testid="department-list">
		{#each departments as department (department.id)}
			<li
				class="flex items-center justify-between gap-2 rounded-md px-2 py-1 hover:bg-surface-sunken"
			>
				<span class="text-sm">{department.name}</span>
				<span class="inline-flex items-center gap-1 whitespace-nowrap">
					<IconAction
						label={m.admin_departments_rename()}
						icon={Pencil}
						size="sm"
						onclick={() => startEdit(department)}
						testid="rename-department"
					/>
					<IconAction
						label={m.admin_users_delete()}
						icon={Trash2}
						size="sm"
						variant="danger"
						onclick={() => remove(department)}
					/>
				</span>
			</li>
		{/each}
	</ul>
</Card>

<Dialog
	open={creating}
	onOpenChange={(open) => {
		if (!open) creating = false;
	}}
	title={m.admin_departments_create_title()}
	data-testid="create-department-dialog"
>
	<form class="flex flex-col gap-3" onsubmit={create}>
		<FormField label={m.admin_departments_new()} for="new-department-name">
			<Input
				id="new-department-name"
				required
				placeholder={m.admin_departments_placeholder()}
				bind:value={draft}
			/>
		</FormField>
		{#if error}
			<p role="alert" class="text-sm text-danger">{error}</p>
		{/if}
		<div class="flex gap-2">
			<Button type="submit" size="sm" data-testid="create-department">
				{m.admin_departments_create()}
			</Button>
			<Button variant="ghost" size="sm" onclick={() => (creating = false)}>
				{m.common_cancel()}
			</Button>
		</div>
	</form>
</Dialog>

<Dialog
	open={editing !== null}
	onOpenChange={(open) => {
		if (!open) editing = null;
	}}
	title={m.admin_department_edit_title()}
	data-testid="department-dialog"
>
	{#if editing}
		{@const department = editing}
		<div class="flex flex-col gap-3">
			<FormField label={m.admin_departments_title()} for="edit-department-name">
				<Input
					id="edit-department-name"
					placeholder={m.admin_departments_placeholder()}
					bind:value={draft}
				/>
			</FormField>
			{#if error}
				<p role="alert" class="text-sm text-danger">{error}</p>
			{/if}
			<div class="flex gap-2">
				<Button size="sm" onclick={() => save(department)} data-testid="save-department">
					{m.admin_users_save()}
				</Button>
				<Button variant="ghost" size="sm" onclick={() => (editing = null)}>
					{m.common_cancel()}
				</Button>
			</div>
		</div>
	{/if}
</Dialog>

<ConfirmDialog
	open={confirmRequest !== null}
	title={confirmRequest?.title ?? ''}
	message={confirmRequest?.message ?? ''}
	onConfirm={() => confirmRequest?.run()}
	onClose={() => (confirmRequest = null)}
/>
