import { error } from '@sveltejs/kit';
import { marked } from 'marked';
import type { PageServerLoad } from './$types';
import { getBook, listChapterIdx } from '$lib/server/pocketbase';
import { log } from '$lib/server/logger';
import { backendFetch } from '$lib/server/scraper';
import type { Voice } from '$lib/types';

const SUPPORTED_LANGS = new Set(['ru', 'id', 'pt', 'fr']);

export const load: PageServerLoad = async ({ params, url, locals }) => {
	const { slug } = params;
	const n = parseInt(params.n, 10);

	if (!n || n < 1) error(400, 'Invalid chapter number');

	const isPreview = url.searchParams.get('preview') === '1';
	const chapterUrl = url.searchParams.get('chapter_url') ?? '';
	const chapterTitle = url.searchParams.get('title') ?? '';
	const rawLang = url.searchParams.get('lang') ?? '';
	// Non-pro users can only read EN — silently ignore lang param
	const lang = locals.isPro && SUPPORTED_LANGS.has(rawLang) ? rawLang : '';
	const useTranslation = lang !== '';

	if (isPreview) {
		// ── Preview path: scrape chapter live, nothing from PocketBase/MinIO ──
		const previewParams = new URLSearchParams();
		if (chapterUrl) previewParams.set('chapter_url', chapterUrl);
		if (chapterTitle) previewParams.set('title', chapterTitle);

		let chapterData: { slug: string; number: number; title: string; text: string; url: string };
		try {
			const res = await backendFetch(
				`/api/chapter-text-preview/${encodeURIComponent(slug)}/${n}?${previewParams.toString()}`
			);
			if (!res.ok) {
				log.error('chapter', 'chapter-text-preview returned error', { slug, n, status: res.status });
				error(404, `Chapter ${n} not found`);
			}
			chapterData = await res.json();
		} catch (e) {
			if (e instanceof Error && 'status' in e) throw e;
			log.error('chapter', 'chapter-text-preview fetch failed', { slug, n, err: String(e) });
			error(502, 'Could not fetch chapter preview');
		}

		// Wrap plain text in minimal HTML paragraphs for display
		const html = chapterData.text
			? '<p>' + chapterData.text.replace(/\n{2,}/g, '</p><p>').replace(/\n/g, '<br>') + '</p>'
			: '';

		// Fetch voices (non-critical for preview)
		let voices: Voice[] = [];
		try {
			const vRes = await backendFetch('/api/voices');
			if (vRes.ok) {
				const d = (await vRes.json()) as { voices: Voice[] };
				voices = d.voices ?? [];
			}
		} catch {
			// Non-critical
		}

		// Try to get book title/cover from PocketBase for breadcrumbs; fall back to slug
		const pb = await getBook(slug).catch(() => null);

		return {
			book: {
				slug,
				title: pb?.title ?? slug,
				cover: pb?.cover ?? ''
			},
			chapter: {
				id: '',
				slug,
				number: n,
				title: chapterData.title || `Chapter ${n}`,
				date_label: ''
			},
			html,
			voices,
			prev: null as number | null,
			next: null as number | null,
			chapters: [] as { number: number; title: string }[],
			sessionId: locals.sessionId,
			isPreview: true,
			lang: '',
			translationStatus: 'unavailable' as string,
			isPro: locals.isPro,
			chapterImageUrl: null as string | null
		};
	}

	// ── Normal path: fetch from PocketBase + MinIO ─────────────────────────
	// Fetch book metadata, chapter index, voice list, and chapter image check in parallel.
	// HEAD /api/chapter-image checks existence cheaply without downloading the image.
	const [book, chapters, voicesRes, chapterImageRes] = await Promise.all([
		getBook(slug),
		listChapterIdx(slug),
		backendFetch('/api/voices').catch(() => null),
		backendFetch(`/api/chapter-image/novelfire.net/${encodeURIComponent(slug)}/${n}`, { method: 'HEAD' }).catch(() => null)
	]);

	if (!book) error(404, `Book "${slug}" not found`);

	const chapterIdx = chapters.find((c) => c.number === n);
	if (!chapterIdx) error(404, `Chapter ${n} not found`);

	// Chapter image URL — only set when a generated image exists for this chapter
	const chapterImageUrl =
		chapterImageRes?.ok
			? `/api/chapter-image/novelfire.net/${encodeURIComponent(slug)}/${n}`
			: null;

	// Parse voices — fall back to empty list on error
	let voices: Voice[] = [];
	try {
		if (voicesRes?.ok) {
			const data = (await voicesRes.json()) as { voices: Voice[] };
			voices = data.voices ?? [];
		}
	} catch {
		// Non-critical — UI will use store default
	}

	// ── Translation path: try to serve translated HTML ─────────────────────
	if (useTranslation) {
		try {
			const tRes = await backendFetch(
				`/api/translation/${encodeURIComponent(slug)}/${n}?lang=${lang}`
			);
			if (tRes.ok) {
				const tData = (await tRes.json()) as { html: string; lang: string };
				const prevChapter = chapters.find((c) => c.number === n - 1) ?? null;
				const nextChapter = chapters.find((c) => c.number === n + 1) ?? null;
			return {
				book: { slug: book.slug, title: book.title, cover: book.cover ?? '' },
				chapter: chapterIdx,
				html: tData.html,
				voices,
				prev: prevChapter ? prevChapter.number : null,
				next: nextChapter ? nextChapter.number : null,
				chapters: chapters.map((c) => ({ number: c.number, title: c.title })),
			sessionId: locals.sessionId,
			isPreview: false,
			lang,
			translationStatus: 'done',
			isPro: locals.isPro,
			chapterImageUrl
				};
			}
			// 404 = not generated yet — fall through to original, UI can trigger generation
		} catch {
			// Non-critical — fall through to original content
		}
	}

	// ── Original content path ──────────────────────────────────────────────
	let html = '';
	try {
		const res = await backendFetch(`/api/chapter-markdown/${encodeURIComponent(slug)}/${n}`);
		if (!res.ok) {
			log.error('chapter', 'chapter-markdown returned error', { slug, n, status: res.status });
			error(res.status === 404 ? 404 : 502, res.status === 404 ? `Chapter ${n} not found` : 'Could not fetch chapter content');
		}
		const markdown = await res.text();
		html = await marked(markdown);
	} catch (e) {
		if (e instanceof Error && 'status' in e) throw e;
		// Don't hard-fail — show empty content with error message
		log.error('chapter', 'failed to fetch chapter content', { slug, n, err: String(e) });
		error(502, 'Could not fetch chapter content');
	}

	// Check translation status for the UI switcher (non-blocking)
	let translationStatus = 'idle';
	if (useTranslation) {
		try {
			const stRes = await backendFetch(
				`/api/translation/status/${encodeURIComponent(slug)}/${n}?lang=${lang}`
			);
			if (stRes.ok) {
				const stData = (await stRes.json()) as { status: string };
				translationStatus = stData.status ?? 'idle';
			}
		} catch {
			// Non-critical
		}
	}

	const prevChapter = chapters.find((c) => c.number === n - 1) ?? null;
	const nextChapter = chapters.find((c) => c.number === n + 1) ?? null;

	return {
		book: { slug: book.slug, title: book.title, cover: book.cover ?? '' },
		chapter: chapterIdx,
		html,
		voices,
		prev: prevChapter ? prevChapter.number : null,
		next: nextChapter ? nextChapter.number : null,
		chapters: chapters.map((c) => ({ number: c.number, title: c.title })),
		sessionId: locals.sessionId,
		isPreview: false,
		lang: useTranslation ? lang : '',
		translationStatus,
		isPro: locals.isPro,
		chapterImageUrl
	};
};
