<script lang="ts">
	/**
	 * Caricamento di un video direttamente su Bunny (TUS, riprendibile), poi attesa
	 * della conversione. La lezione passa al video nuovo quando è pronto.
	 */
	import { invalidateAll } from '$app/navigation';
	import { onDestroy } from 'svelte';
	import * as tus from 'tus-js-client';
	import { segnalaErrore } from '$lib/errori-browser';

	let { lezioneId, abilitato }: { lezioneId: number; abilitato: boolean } = $props();
	const MAX_MINUTI = 10;

	let fase = $state<'' | 'controllo' | 'caricamento' | 'elaborazione' | 'pronto' | 'errore'>('');
	let percentuale = $state(0);
	let messaggio = $state('');
	let avviso = $state('');
	let attesa: ReturnType<typeof setInterval> | undefined;
	let caricamento: tus.Upload | undefined;

	onDestroy(() => {
		clearInterval(attesa);
	});

	function durataFile(file: File): Promise<number> {
		return new Promise((ok) => {
			const v = document.createElement('video');
			const indirizzo = URL.createObjectURL(file);
			// Prima si stacca il file dall'elemento e poi si libera l'indirizzo: al contrario il
			// browser continua a leggerlo e segnala in console un errore di file non trovato
			const fine = (durata: number) => {
				v.removeAttribute('src');
				v.load();
				URL.revokeObjectURL(indirizzo);
				ok(durata);
			};
			v.preload = 'metadata';
			v.onloadedmetadata = () => fine(v.duration);
			v.onerror = () => fine(NaN);
			v.src = indirizzo;
		});
	}

	async function scelta(e: Event) {
		const input = e.currentTarget as HTMLInputElement;
		const file = input.files?.[0];
		input.value = '';
		if (!file) return;
		messaggio = '';
		avviso = '';
		fase = 'controllo';
		const d = await durataFile(file);
		if (d > MAX_MINUTI * 60 + 5) avviso = `Il video dura ${Math.floor(d / 60)} minuti e ${Math.round(d % 60)} secondi: le lezioni dovrebbero stare sotto i ${MAX_MINUTI} minuti. Lo carico lo stesso.`;

		try {
			const r = await fetch('/admin/api/video', {
				method: 'POST',
				headers: { 'content-type': 'application/json' },
				body: JSON.stringify({ lezioneId, nomeFile: file.name })
			});
			if (!r.ok) throw new Error(await r.text());
			const f = await r.json();
			fase = 'caricamento';
			percentuale = 0;
			await new Promise<void>((ok, ko) => {
				caricamento = new tus.Upload(file, {
					endpoint: f.endpoint,
					retryDelays: [0, 3000, 5000, 10000, 20000, 60000],
					headers: {
						AuthorizationSignature: f.firma,
						AuthorizationExpire: String(f.scadenza),
						VideoId: f.videoId,
						LibraryId: String(f.libreria)
					},
					metadata: { filetype: file.type, title: file.name },
					onProgress: (fatti, totale) => (percentuale = Math.round((fatti / totale) * 100)),
					onSuccess: () => ok(),
					onError: (err) => ko(err)
				});
				caricamento.start();
			});
			await fetch(`/admin/api/video/${f.versioneId}`, { method: 'POST' });
			fase = 'elaborazione';
			attesa = setInterval(async () => {
				const s = await fetch(`/admin/api/video/${f.versioneId}`).then((x) => x.json());
				if (s.stato === 'pronto' || s.stato === 'errore') {
					clearInterval(attesa);
					fase = s.stato;
					if (s.stato === 'errore') {
						messaggio = 'Bunny non è riuscito a convertire il video. Prova a esportarlo di nuovo in MP4.';
						segnalaErrore('Bunny: conversione non riuscita', { dettaglio: { lezioneId, versioneId: f.versioneId, file: file.name, tipo: file.type, byte: file.size } });
					}
					await invalidateAll();
				}
			}, 8000);
		} catch (err) {
			console.error(err);
			fase = 'errore';
			messaggio = 'Il caricamento non è andato a buon fine. Controlla la connessione e riprova.';
			const codice = await segnalaErrore(err, { dettaglio: { lezioneId, file: file.name, tipo: file.type, byte: file.size, percentuale, errore: String(err) } });
			if (codice) messaggio += ` (codice ${codice})`;
		}
	}

	function annulla() {
		caricamento?.abort();
		fase = '';
	}
</script>

{#if !abilitato}
	<p class="rounded-md border border-dashed border-linea bg-sfondo p-4 text-sm text-grigio">
		Il caricamento dei video si attiva quando la piattaforma è collegata a Bunny Stream.
	</p>
{:else}
	<div class="space-y-3">
		{#if fase === 'caricamento'}
			<div class="h-2 overflow-hidden rounded-full bg-sfondo"><div class="h-full bg-brand-500 transition-all" style="width:{percentuale}%"></div></div>
			<p class="text-sm">Caricamento {percentuale}%. Non chiudere la pagina.</p>
			<button type="button" class="btn btn-secondario btn-piccolo" onclick={annulla}>Annulla</button>
		{:else if fase === 'elaborazione'}
			<p class="text-sm">Video caricato. Bunny lo sta convertendo: di solito ci vogliono pochi minuti. La pagina si aggiorna da sola.</p>
		{:else}
			<label class="btn btn-primario cursor-pointer">
				{fase === 'controllo' ? 'Controllo il file…' : 'Carica un video'}
				<input type="file" accept="video/*" class="sr-only" onchange={scelta} disabled={fase === 'controllo'} />
			</label>
			{#if fase === 'pronto'}<p class="avviso-ok">Video pronto: la lezione ora usa questo.</p>{/if}
		{/if}
		{#if avviso}<p class="text-sm text-amber-800">{avviso}</p>{/if}
		{#if messaggio}<p class="avviso-errore">{messaggio}</p>{/if}
	</div>
{/if}
