import { json, error } from '@sveltejs/kit';
import { marked } from 'marked';
import type { RequestHandler } 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';

/**
 * GET /api/chapter/[slug]/[n]
 * Returns rendered chapter HTML, navigation info, and voice list.
 * Supports ?preview=1&chapter_url=...&title=... for un-scraped books.
 *
 * Response shape mirrors ChapterResponse in the iOS APIClient.
 */
export const GET: RequestHandler = 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') ?? '';

	if (isPreview) {
		// Preview path: scrape 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('api/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('api/chapter', 'chapter-text-preview fetch failed', { slug, n, err: String(e) });
			error(502, 'Could not fetch chapter preview');
		}

		const html = chapterData.text
			? '<p>' + chapterData.text.replace(/\n{2,}/g, '</p><p>').replace(/\n/g, '<br>') + '</p>'
			: '';

		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
		}

		const pb = await getBook(slug).catch(() => null);

		return json({
			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,
			next: null,
			chapters: [],
			is_preview: true
		});
	}

	// Normal path: PocketBase + MinIO
	const [book, chapters, voicesRes] = await Promise.all([
		getBook(slug),
		listChapterIdx(slug),
		backendFetch('/api/voices').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`);

	let voices: Voice[] = [];
	try {
		if (voicesRes?.ok) {
			const data = (await voicesRes.json()) as { voices: Voice[] };
			voices = data.voices ?? [];
		}
	} catch {
		// Non-critical
	}

	let html = '';
	try {
		const res = await backendFetch(`/api/chapter-markdown/${encodeURIComponent(slug)}/${n}`);
		if (!res.ok) {
			log.error('api/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 = marked(markdown) as string;
	} catch (e) {
		if (e instanceof Error && 'status' in e) throw e;
		log.error('api/chapter', 'failed to fetch chapter content', { slug, n, err: String(e) });
		error(502, 'Could not fetch chapter content');
	}

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

	return json({
		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 })),
		is_preview: false
	});
};
