// attachment is the frontend half deliberately deferred in Schritt 7 (see
// modules/field_types/README.md) -- same reasoning as links: display and interaction
// merge into one always-live cell, so this ships only "attachment-cell",
// used for both read and write (no separate edit_tag), same shape as
// boolean-cell/links-cell.
//
// This module never uploads/deletes anything itself: it only dispatches
// "upload" (detail: {file}, a real File object -- CustomEvent.detail can
// hold any value, no serialization needed for a same-realm DOM event) and
// "delete" (detail: {fileId}) CustomEvents. DataGrid.svelte wires those to
// the SAME onUploadAttachment/onDeleteAttachment props the native upload
// button/delete "×" already call -- the actual mutation + refresh
// (invalidateAll()) stays exactly where it already was, unchanged. The
// attachment/thumbnail URLs themselves need no fetch() at all: same-origin
// <img src>/<a href> already send the session cookie automatically, same as
// frontend/src/lib/api/attachments.ts's attachmentUrl/attachmentThumbnailUrl.
//
// Deliberate simplification (documented, not silently dropped): no
// upload-in-flight spinner or per-file "deleting" disabled state. The
// native AttachmentCell.svelte can show one because onUpload/onDelete are
// awaited promises; a CustomEvent is fire-and-forget with no return value
// to await, so there's nothing to tie a busy-state to here. The cell
// re-renders with fresh data automatically once the host's own
// invalidateAll() finishes -- just without a spinner during the gap.
function attachmentBasePath(tableId, pk, columnId, fileId) {
	return `/api/v1/tables/${tableId}/records/${pk}/attachments/${columnId}/${fileId}`;
}

function isImage(file) {
	return typeof file.mime_type === 'string' && file.mime_type.indexOf('image/') === 0 && file.has_thumbnail;
}

function openLightbox(src, alt) {
	const overlay = document.createElement('div');
	overlay.className = 'fixed inset-0 z-[9999] grid place-items-center bg-ink-950/80 p-4';
	const wrap = document.createElement('div');
	wrap.className = 'relative max-h-[90vh] max-w-[90vw]';
	const img = document.createElement('img');
	img.src = src;
	img.alt = alt;
	img.className = 'max-h-[90vh] max-w-[90vw] rounded shadow-2xl';
	const closeBtn = document.createElement('button');
	closeBtn.type = 'button';
	closeBtn.className =
		'absolute -top-3 -right-3 flex size-8 items-center justify-center rounded-full bg-surface text-ink-700 shadow hover:bg-ink-100';
	closeBtn.setAttribute('aria-label', 'Close');
	closeBtn.textContent = '×';
	function close() {
		document.removeEventListener('keydown', onKeydown);
		overlay.remove();
	}
	function onKeydown(e) {
		if (e.key === 'Escape') close();
	}
	closeBtn.addEventListener('click', close);
	document.addEventListener('keydown', onKeydown);
	wrap.appendChild(img);
	wrap.appendChild(closeBtn);
	overlay.appendChild(wrap);
	document.body.appendChild(overlay);
}

customElements.define(
	'attachment-cell',
	class extends HTMLElement {
		static get observedAttributes() {
			return ['value', 'editable', 'table-id', 'pk', 'column-id', 'aria-label'];
		}

		connectedCallback() {
			this.render();
		}

		attributeChangedCallback() {
			this.render();
		}

		_files() {
			try {
				const parsed = JSON.parse(this.getAttribute('value') ?? 'null');
				return Array.isArray(parsed) ? parsed : [];
			} catch {
				return [];
			}
		}

		_pk() {
			try {
				return JSON.parse(this.getAttribute('pk') ?? 'null');
			} catch {
				return null;
			}
		}

		render() {
			this.innerHTML = '';
			this.className = 'flex flex-wrap items-center gap-1.5 overflow-hidden';
			const editable = this.getAttribute('editable') === 'true';
			const tableId = this.getAttribute('table-id');
			const columnId = this.getAttribute('column-id');
			const pk = this._pk();

			for (const file of this._files()) {
				const base = attachmentBasePath(tableId, pk, columnId, file.id);
				if (isImage(file)) {
					const wrap = document.createElement('span');
					wrap.className = 'group/file relative inline-flex shrink-0';
					const openBtn = document.createElement('button');
					openBtn.type = 'button';
					openBtn.className = 'block rounded';
					openBtn.title = file.original_filename;
					const img = document.createElement('img');
					img.src = base + '/thumbnail';
					img.alt = file.original_filename;
					img.loading = 'lazy';
					img.className = 'size-8 rounded border border-ink-200 object-cover';
					openBtn.appendChild(img);
					openBtn.addEventListener('click', () => openLightbox(base, file.original_filename));
					wrap.appendChild(openBtn);
					if (editable) wrap.appendChild(this._deleteButton(file, 'thumbnail'));
					this.appendChild(wrap);
				} else {
					const chip = document.createElement('span');
					chip.className = 'badge inline-flex shrink-0 items-center gap-1 bg-ink-100 text-ink-700';
					const link = document.createElement('a');
					link.href = base;
					link.target = '_blank';
					link.rel = 'noopener';
					link.className = 'max-w-[8rem] truncate hover:underline';
					link.title = file.original_filename;
					link.textContent = file.original_filename;
					chip.appendChild(link);
					if (editable) chip.appendChild(this._deleteButton(file, 'chip'));
					this.appendChild(chip);
				}
			}

			if (editable) {
				const fileInput = document.createElement('input');
				fileInput.type = 'file';
				fileInput.className = 'hidden';
				fileInput.addEventListener('change', () => {
					const file = fileInput.files && fileInput.files[0];
					fileInput.value = '';
					if (!file) return;
					this.dispatchEvent(new CustomEvent('upload', { detail: { file }, bubbles: true }));
				});
				this.appendChild(fileInput);

				const trigger = document.createElement('button');
				trigger.type = 'button';
				trigger.className =
					'badge shrink-0 bg-ink-100 text-ink-500 hover:bg-ink-200 hover:text-ink-700';
				trigger.setAttribute('aria-label', this.getAttribute('aria-label') || 'Upload');
				trigger.textContent = '+';
				trigger.addEventListener('click', () => fileInput.click());
				this.appendChild(trigger);
			}
		}

		_deleteButton(file, variant) {
			const btn = document.createElement('button');
			btn.type = 'button';
			// "thumbnail": overlaid on the image, hidden until the surrounding
			// group/file wrapper is hovered. "chip": inline next to the
			// filename, always visible -- same two treatments as
			// AttachmentCell.svelte's image-vs-chip branches.
			btn.className =
				variant === 'thumbnail'
					? 'absolute -top-1.5 -right-1.5 hidden size-4 items-center justify-center rounded-full bg-red-600 text-[10px] leading-none text-white group-hover/file:flex'
					: 'rounded-full text-ink-400 hover:text-red-600';
			btn.setAttribute('aria-label', 'Delete ' + file.original_filename);
			btn.textContent = '×';
			btn.addEventListener('click', () => {
				this.dispatchEvent(new CustomEvent('delete', { detail: { fileId: file.id }, bubbles: true }));
			});
			return btn;
		}
	}
);
