<!--
  RegistryImagePicker — optional "browse images" affordance for the
  registry trigger's image field.

  The registry trigger config carries only a fully-qualified image `ref`
  (no registry id). On open, this loads every configured registry's
  images and lists them in a single command palette, GROUPED by registry,
  so the operator picks a fully-qualified ref without typing it. Selecting
  a row calls `onpick(full_ref, registry_name)`; the parent writes the ref
  into its config and may use the registry name to auto-select the source
  registry. Manual text entry in the parent input is always preserved — the
  picker is purely additive convenience.

  Lives in its own component (rather than inline in TriggerKindForm)
  because that form binds a prop named `state`, which shadows Svelte 5's
  `$state` rune. Isolating the reactive picker state here sidesteps the
  collision, and keeps the only in-flow element a single button so it
  drops cleanly into the field's input row.
-->
<script lang="ts">
	import EntityPicker from '$lib/components/EntityPicker.svelte';
	import { IconBox } from '$lib/components/icons';
	import * as api from '$lib/api';
	import type { EntityPickerItem } from '$lib/types';
	import { t } from '$lib/i18n';

	interface Props {
		/** Current image ref — highlights the matching row in the picker. */
		current?: string;
		/**
		 * Called with the chosen image's full_ref and the name of the registry
		 * it came from. Callers that only care about the ref (e.g. the registry
		 * trigger form) can ignore the second argument.
		 */
		onpick: (fullRef: string, registryName: string) => void;
	}

	let { current = '', onpick }: Props = $props();

	let open = $state(false);
	let loading = $state(false);
	let loaded = $state(false);
	let items = $state<EntityPickerItem[]>([]);

	// Lazily load every registry's images the first time the operator
	// opens the picker, flattened into one grouped list. Per-registry
	// failures are tolerated (other registries still populate). A total
	// failure leaves the list empty — the picker then shows its built-in
	// "no results" state — and never blocks manual entry in the field.
	async function ensureLoaded(): Promise<void> {
		if (loaded || loading) return;
		loading = true;
		try {
			const registries = await api.listRegistries();
			const collected: EntityPickerItem[] = [];
			await Promise.all(
				registries.map(async (reg) => {
					try {
						const images = await api.listRegistryImages(reg.id);
						for (const img of images) {
							collected.push({
								value: img.full_ref,
								label: img.full_ref,
								description: img.owner ? `${img.owner}/${img.name}` : img.name,
								group: reg.name,
								icon: 'box'
							});
						}
					} catch {
						// Skip a registry we can't reach; others still load.
					}
				})
			);
			items = collected;
			loaded = true;
		} catch {
			// Total failure (e.g. /api/registries unreachable): leave items
			// empty so the picker shows its empty state. Do NOT mark loaded
			// so a later open retries.
			items = [];
		} finally {
			loading = false;
		}
	}

	async function openPicker(): Promise<void> {
		await ensureLoaded();
		open = true;
	}

	function handleSelect(value: string): void {
		// Each picker row carries its source registry name in `group` (set when
		// the list was built). Surface it so callers can auto-select the
		// registry the image came from. Falls back to '' (public) if not found.
		const picked = items.find((i) => i.value === value);
		onpick(value, picked?.group ?? '');
		open = false;
	}
</script>

<button
	type="button"
	class="browse-btn"
	onclick={openPicker}
	disabled={loading}
	title={$t('redeployTriggers.form.browseImagesHint')}
>
	<IconBox size={13} />
	<span>{$t('redeployTriggers.form.browseImages')}</span>
</button>

<EntityPicker
	bind:open
	{items}
	{current}
	title={$t('redeployTriggers.form.browseImagesTitle')}
	placeholder={$t('redeployTriggers.form.browseImagesSearch')}
	onselect={handleSelect}
	onclose={() => (open = false)}
/>

<style>
	.browse-btn {
		display: inline-flex;
		align-items: center;
		gap: 0.35rem;
		padding: 0 0.7rem;
		background: var(--surface-card);
		border: 1px solid var(--border-primary);
		border-radius: var(--radius-md);
		font-family: var(--forge-mono);
		font-size: 0.58rem;
		font-weight: 600;
		letter-spacing: 0.1em;
		text-transform: uppercase;
		color: var(--text-secondary);
		cursor: pointer;
		transition: border-color 120ms ease, color 120ms ease, background 120ms ease;
		white-space: nowrap;
	}
	.browse-btn:hover:not(:disabled) {
		border-color: var(--forge-accent);
		color: var(--text-primary);
		background: var(--surface-card-hover);
	}
	.browse-btn:disabled {
		opacity: 0.5;
		cursor: not-allowed;
	}
	.browse-btn:focus-visible {
		outline: 2px solid var(--border-focus);
		outline-offset: 2px;
	}
</style>
