import type { PageServerLoad } from './$types';
import {
	getBooksBySlugs,
	recentlyUpdatedBooks,
	allProgress,
	getHomeStats,
	getSubscriptionFeed,
	getTrendingBooks,
	getRecommendedBooks
} from '$lib/server/pocketbase';
import { log } from '$lib/server/logger';
import type { Book, Progress } from '$lib/server/pocketbase';

function parseGenresLocal(genres: string[] | string | null | undefined): string[] {
	if (!genres) return [];
	if (Array.isArray(genres)) return genres;
	try { return JSON.parse(genres) as string[]; } catch { return []; }
}

function computeStreak(progressList: Progress[]): number {
	const days = new Set(
		progressList.filter((p) => p.updated).map((p) => p.updated.slice(0, 10))
	);
	let streak = 0;
	const today = new Date();
	for (let i = 0; i < 365; i++) {
		const d = new Date(today);
		d.setUTCDate(d.getUTCDate() - i);
		if (days.has(d.toISOString().slice(0, 10))) streak++;
		else if (i > 0) break;
	}
	return streak;
}

export const load: PageServerLoad = async ({ locals }) => {
	let recentBooks: Book[] = [];
	let progressList: Progress[] = [];
	let stats = { totalBooks: 0, totalChapters: 0 };

	try {
		[recentBooks, progressList, stats] = await Promise.all([
			recentlyUpdatedBooks(8).catch(() => [] as Book[]),
			allProgress(locals.sessionId, locals.user?.id),
			getHomeStats()
		]);
	} catch (e) {
		log.error('home', 'failed to load home data', { err: String(e) });
	}

	const streak = computeStreak(progressList);

	// Fetch only the books we need for continue-reading (avoid loading all books)
	const progressSlugs = progressList.map((p) => p.slug);
	const progressBooks = progressSlugs.length > 0
		? await getBooksBySlugs(progressSlugs).catch(() => [] as Book[])
		: [];

	const bookMap = new Map<string, Book>(progressBooks.map((b) => [b.slug, b]));

	// All continue-reading entries joined with book data, most recent first
	const continueReading = progressList
		.filter((p) => bookMap.has(p.slug))
		.slice(0, 8)
		.map((p) => ({ book: bookMap.get(p.slug)!, chapter: p.chapter }));

	// Split into in-progress vs completed
	const continueInProgress = continueReading.filter(
		({ book, chapter }) => book.total_chapters === 0 || chapter < book.total_chapters
	);
	const continueCompleted = continueReading.filter(
		({ book, chapter }) => book.total_chapters > 0 && chapter >= book.total_chapters
	);

	// Top genres from books the user has been reading
	const genreFreq = new Map<string, number>();
	for (const { book } of continueReading) {
		for (const g of parseGenresLocal(book.genres)) {
			genreFreq.set(g, (genreFreq.get(g) ?? 0) + 1);
		}
	}
	const topGenres = [...genreFreq.entries()]
		.sort((a, b) => b[1] - a[1])
		.slice(0, 3)
		.map(([g]) => g);

	// Deduplicate recently-updated against in-progress slugs
	const inProgressSlugs = new Set(continueReading.map((c) => c.book.slug));
	const recentlyUpdated = recentBooks.filter((b) => !inProgressSlugs.has(b.slug)).slice(0, 6);

	// Fetch trending, recommendations, and subscription feed in parallel
	const [trendingBooks, recommendedBooks, subscriptionFeed] = await Promise.all([
		getTrendingBooks(8).catch(() => [] as Book[]),
		topGenres.length > 0
			? getRecommendedBooks(topGenres, inProgressSlugs, 8).catch(() => [] as Book[])
			: Promise.resolve([] as Book[]),
		locals.user
			? getSubscriptionFeed(locals.user.id, 12).catch((e) => {
					log.error('home', 'failed to load subscription feed', { err: String(e) });
					return [] as Awaited<ReturnType<typeof getSubscriptionFeed>>;
				})
			: Promise.resolve([])
	]);

	// Strip books the user is already reading from trending (redundant)
	const trendingFiltered = trendingBooks.filter((b) => !inProgressSlugs.has(b.slug));

	return {
		continueInProgress,
		continueCompleted,
		recentlyUpdated,
		subscriptionFeed,
		trendingBooks: trendingFiltered,
		recommendedBooks,
		topGenre: topGenres[0] ?? null,
		stats: {
			...stats,
			booksInProgress: continueInProgress.length,
			streak
		}
	};
};
