<script lang="ts">
	import { apiMutate } from '$lib/api/client.js';
	import type { ApiKey, ApiKeyCreate, ApiKeyCreated, ApiKeyRole } from '$lib/api/types.js';
	import { Button } from '@evobgp/ui/components/button/index.js';
	import {
		Card,
		CardContent,
		CardDescription,
		CardHeader,
		CardTitle
	} from '@evobgp/ui/components/card/index.js';
	import {
		Dialog,
		DialogContent,
		DialogDescription,
		DialogFooter,
		DialogHeader,
		DialogTitle
	} from '@evobgp/ui/components/dialog/index.js';
	import {
		Select,
		SelectContent,
		SelectItem,
		SelectTrigger
	} from '@evobgp/ui/components/select/index.js';
	import FormField from '$lib/components/patterns/form/form-field.svelte';
	import AppInput from '$lib/components/patterns/form/app-input.svelte';
	import AppDataTable from '$lib/components/patterns/data-table/app-data-table.svelte';
	import { confirm } from '$lib/components/patterns/confirm/confirm-state.svelte.js';
	import { notify, notifyApiError } from '$lib/ui/app/toast.js';
	import Plus from '@lucide/svelte/icons/plus';
	import Trash2 from '@lucide/svelte/icons/trash-2';
	import RefreshCw from '@lucide/svelte/icons/refresh-cw';
	import Copy from '@lucide/svelte/icons/copy';

	type Props = {
		items: ApiKey[];
		loading?: boolean;
		initialLoading?: boolean;
		error?: string | null;
		onRefresh: () => void | Promise<void>;
	};

	let { items, loading = false, initialLoading = false, error = null, onRefresh }: Props = $props();

	const roleOptions: Array<{ value: ApiKeyRole; label: string }> = [
		{ value: 'viewer', label: 'viewer — только чтение' },
		{ value: 'editor', label: 'editor — CRUD без apply' },
		{ value: 'operator', label: 'operator — полный доступ' },
		{ value: 'node', label: 'node — только API ноды' }
	];

	let dialogOpen = $state(false);
	let tokenDialogOpen = $state(false);
	let revealedToken = $state('');
	let form = $state<ApiKeyCreate>({ name: '', role: 'editor' });
	let expiresLocal = $state('');
	let saving = $state(false);

	const columns = [
		{ id: 'name', label: 'Имя', sortable: true, sortValue: (k: ApiKey) => k.name },
		{ id: 'role', label: 'Роль', sortable: true, sortValue: (k: ApiKey) => k.role },
		{ id: 'prefix', label: 'Префикс', sortable: true, sortValue: (k: ApiKey) => k.prefix },
		{
			id: 'revoked',
			label: 'Статус',
			sortable: true,
			sortValue: (k: ApiKey) => (k.revoked_at ? 1 : 0)
		},
		{ id: 'actions', label: '', class: 'w-24' }
	] as const;

	function openCreate() {
		form = { name: '', role: 'editor' };
		expiresLocal = '';
		dialogOpen = true;
	}

	function showToken(created: ApiKeyCreated) {
		revealedToken = created.token;
		tokenDialogOpen = true;
	}

	async function copyToken() {
		try {
			await navigator.clipboard.writeText(revealedToken);
			notify.success('Скопировано');
		} catch {
			notify.error('Не удалось скопировать');
		}
	}

	function requestRevoke(k: ApiKey) {
		if (k.revoked_at) return;
		void confirm({
			title: 'Отозвать API-ключ?',
			description: `${k.name} (${k.prefix}…)`,
			confirmLabel: 'Отозвать',
			destructive: true,
			onConfirm: async () => {
				await apiMutate(`/v1/api-keys/${k.id}`, 'DELETE', undefined, { idempotent: false });
				notify.success('Ключ отозван');
				await onRefresh();
			}
		});
	}

	function requestRotate(k: ApiKey) {
		if (k.revoked_at) return;
		void confirm({
			title: 'Ротировать ключ?',
			description: 'Старый токен перестанет работать сразу.',
			confirmLabel: 'Ротировать',
			onConfirm: async () => {
				try {
					const out = await apiMutate<ApiKeyCreated>(
						`/v1/api-keys/${k.id}/rotate`,
						'POST',
						undefined,
						{ idempotent: false }
					);
					notify.success('Ключ обновлён');
					showToken(out);
					await onRefresh();
				} catch (e) {
					notifyApiError(e);
				}
			}
		});
	}

	async function save() {
		if (!form.name.trim()) {
			notify.error('Укажите имя');
			return;
		}
		saving = true;
		try {
			const body: ApiKeyCreate = {
				name: form.name.trim(),
				role: form.role
			};
			if (expiresLocal.trim()) {
				const d = new Date(expiresLocal);
				if (Number.isNaN(d.getTime())) {
					notify.error('Некорректная дата истечения');
					return;
				}
				body.expires_at = d.toISOString();
			}
			const created = await apiMutate<ApiKeyCreated>('/v1/api-keys', 'POST', body);
			notify.success('Ключ создан');
			dialogOpen = false;
			showToken(created);
			await onRefresh();
		} catch (e) {
			notifyApiError(e);
		} finally {
			saving = false;
		}
	}
</script>

<Card>
	<CardHeader
		class="flex flex-col gap-3 border-b py-3 sm:flex-row sm:items-center sm:justify-between"
	>
		<div class="min-w-0 flex-1">
			<CardTitle class="text-base">API-ключи</CardTitle>
			<CardDescription>
				Управление ключами tenant. Полный токен показывается только при создании и ротации.
			</CardDescription>
		</div>
		<div class="flex shrink-0 flex-wrap items-center justify-end gap-2">
			<Button size="sm" variant="outline" onclick={() => onRefresh()} disabled={loading}>
				<RefreshCw class={loading ? 'animate-spin' : ''} />
				Обновить
			</Button>
			<Button size="sm" onclick={openCreate}><Plus />Создать</Button>
		</div>
	</CardHeader>
	<CardContent class="p-4 pt-0">
		<AppDataTable
			columns={[...columns]}
			rows={items}
			rowKey={(k) => k.id}
			loading={initialLoading || loading}
			{error}
			emptyTitle="Нет ключей"
			emptyDescription="Создайте API-ключ для автоматизации или отдельного доступа."
		>
			{#snippet cell({ row: k, column })}
				{#if column.id === 'name'}
					<span class="font-medium">{k.name}</span>
				{:else if column.id === 'role'}
					<span class="font-mono text-sm">{k.role}</span>
				{:else if column.id === 'prefix'}
					<span class="font-mono text-xs text-muted-foreground">{k.prefix}…</span>
				{:else if column.id === 'revoked'}
					{#if k.revoked_at}
						<span class="text-sm text-destructive">отозван</span>
					{:else}
						<span class="text-sm text-muted-foreground">активен</span>
					{/if}
				{:else if column.id === 'actions'}
					<div class="flex gap-1">
						<Button
							variant="ghost"
							size="icon-sm"
							title="Ротировать"
							disabled={!!k.revoked_at}
							onclick={() => requestRotate(k)}
						>
							<RefreshCw class="size-3.5" />
						</Button>
						<Button
							variant="ghost"
							size="icon-sm"
							class="text-destructive"
							disabled={!!k.revoked_at}
							onclick={() => requestRevoke(k)}
						>
							<Trash2 class="size-3.5" />
						</Button>
					</div>
				{/if}
			{/snippet}
		</AppDataTable>
	</CardContent>
</Card>

<Dialog bind:open={dialogOpen}>
	<DialogContent class="sm:max-w-sm">
		<DialogHeader>
			<DialogTitle>Новый API-ключ</DialogTitle>
		</DialogHeader>
		<div class="flex flex-col gap-4 py-2">
			<FormField label="Имя" id="key-name" required>
				<AppInput id="key-name" bind:value={form.name} placeholder="CI / оператор UI" />
			</FormField>
			<FormField label="Роль" id="key-role" required>
				<Select
					type="single"
					value={form.role}
					onValueChange={(v) => (form.role = v as ApiKeyRole)}
				>
					<SelectTrigger id="key-role" class="w-full">
						{roleOptions.find((o) => o.value === form.role)?.label ?? form.role}
					</SelectTrigger>
					<SelectContent>
						{#each roleOptions as opt (opt.value)}
							<SelectItem value={opt.value} label={opt.label}>{opt.label}</SelectItem>
						{/each}
					</SelectContent>
				</Select>
			</FormField>
			<FormField label="Истекает (опционально)" id="key-expires">
				<AppInput id="key-expires" type="datetime-local" bind:value={expiresLocal} />
			</FormField>
		</div>
		<DialogFooter>
			<Button variant="outline" onclick={() => (dialogOpen = false)}>Отмена</Button>
			<Button onclick={save} disabled={saving}>
				{saving ? 'Создание…' : 'Создать'}
			</Button>
		</DialogFooter>
	</DialogContent>
</Dialog>

<Dialog bind:open={tokenDialogOpen}>
	<DialogContent class="sm:max-w-md">
		<DialogHeader>
			<DialogTitle>Сохраните токен</DialogTitle>
			<DialogDescription
				>Он больше не будет показан. Скопируйте в безопасное хранилище.</DialogDescription
			>
		</DialogHeader>
		<div class="rounded-md border bg-muted/40 p-3 font-mono text-xs break-all">{revealedToken}</div>
		<DialogFooter>
			<Button variant="outline" onclick={copyToken}><Copy />Копировать</Button>
			<Button onclick={() => (tokenDialogOpen = false)}>Готово</Button>
		</DialogFooter>
	</DialogContent>
</Dialog>
