import type { PageServerLoad } from './$types';
import { redirect } from '@sveltejs/kit';
import auth from '$lib/server/auth';
import prisma from '$lib/server/prisma';
import {
	getActivePromotions,
	buildPromotionIndex,
	selectBestPromotionIndexed
} from '$lib/server/promotionPricing';

const DEFAULT_ITEMS_PER_PAGE = 10;
const MAX_ITEMS_PER_PAGE = 1000;

export const load = (async ({ locals: { user }, url }) => {
	if (await auth.isAdmin(user)) return redirect(303, '/admin/product');

	try {
		const page = Math.max(1, parseInt(url.searchParams.get('page') || '1'));
		const categoriesParam = url.searchParams.get('categories') || '';
		const selectedCategories = categoriesParam
			? categoriesParam
				.split(',')
				.map((id) => parseInt(id))
				.filter((id) => !isNaN(id))
			: [];
		const year = url.searchParams.get('year') || 'all';
		const search = url.searchParams.get('search') || '';
		const limit = Math.min(
			MAX_ITEMS_PER_PAGE,
			Math.max(1, parseInt(url.searchParams.get('limit') || DEFAULT_ITEMS_PER_PAGE.toString()))
		);
		const sort = url.searchParams.get('sort') || 'publication_desc';
		const skip = (page - 1) * limit;

		// Determine sort order
		const getOrderBy = (sortParam: string) => {
			switch (sortParam) {
				case 'price_asc':
					return [{ price: 'asc' as const }];
				case 'price_desc':
					return [{ price: 'desc' as const }];
				case 'name_asc':
					return [{ name: 'asc' as const }];
				case 'publication_asc':
					return [{ publicationDate: 'asc' as const }];
				case 'publication_desc':
					return [{ publicationDate: 'desc' as const }];
				case 'newest':
				default:
					return [{ publicationDate: 'desc' as const }, { name: 'asc' as const }];
			}
		};

		let where: any = { isPublished: true };
		if (selectedCategories.length > 0) {
			where = {
				...where,
				categories: { some: { id: { in: selectedCategories } } }
			};
		}

		// Add search filter if specified
		if (search) {
			where = {
				...where,
				OR: [
					{ name: { contains: search, mode: 'insensitive' } },
					{ description: { contains: search, mode: 'insensitive' } },
					{ citation: { contains: search, mode: 'insensitive' } }
				]
			};
		}

		// Add year filter if specified
		if (year !== 'all') {
			const yearInt = parseInt(year);
			where = {
				...where,
				publicationDate: {
					gte: new Date(`${yearInt}-01-01`),
					lt: new Date(`${yearInt + 1}-01-01`)
				}
			};
		}

		// For category 16, use a different approach to prioritize "Kenya Law" products
		let products, total;

		if (selectedCategories.includes(16) && selectedCategories.length === 1) {
			// For Kenya Law category, maintain sortOrder priority but allow sorting override
			const orderBy = sort === 'newest' || sort === 'publication_desc'
				? [{ sortOrder: 'asc' as const }, { publicationDate: 'desc' as const }]
				: sort === 'publication_asc'
					? [{ sortOrder: 'asc' as const }, { publicationDate: 'asc' as const }]
					: getOrderBy(sort);

			[products, total] = await Promise.all([
				prisma.product.findMany({
					where,
					include: {
						Image: { select: { url: true } },
						categories: true
					},
					orderBy,
					skip,
					take: limit
				}),
				prisma.product.count({ where })
			]);
		} else {
			// Normal query for other categories
			[products, total] = await Promise.all([
				prisma.product.findMany({
					where,
					include: {
						Image: { select: { url: true } },
						categories: true
					},
					orderBy: getOrderBy(sort),
					skip,
					take: limit
				}),
				prisma.product.count({ where })
			]);
		}

		const productFilterForCounts: any = {
			isPublished: true
		};

		if (year !== 'all') {
			const yearInt = parseInt(year);
			productFilterForCounts.publicationDate = {
				gte: new Date(`${yearInt}-01-01`),
				lt: new Date(`${yearInt + 1}-01-01`)
			};
		}

		if (search) {
			productFilterForCounts.OR = [
				{ name: { contains: search, mode: 'insensitive' } },
				{ description: { contains: search, mode: 'insensitive' } },
				{ citation: { contains: search, mode: 'insensitive' } }
			];
		}

		const categoriesWithCounts = await prisma.category.findMany({
			orderBy: { sortOrder: 'asc' },
			include: {
				_count: {
					select: {
						Products: { where: productFilterForCounts }
					}
				}
			}
		});

		const categoryCounts = categoriesWithCounts.map(({ _count, ...category }) => ({
			...category,
			count: _count.Products
		}));

		// Centralized + indexed promotion application (refactor: remove duplicate logic & improve scalability)
		// Limit active promotion fetch to only those touching displayed products/categories
		const allCategoryIds = Array.from(new Set(products.flatMap((p: any) => p.categories.map((c: any) => c.id))));
		const activePromotions = await getActivePromotions(new Date(), {
			productIds: products.map((p: any) => p.id),
			categoryIds: allCategoryIds
		});
		const promoIndex = buildPromotionIndex(activePromotions);
		const productsWithPricing = products.map((p) => {
			const categoryIds = p.categories.map((c: any) => c.id);
			const applied = selectBestPromotionIndexed(p.price, p.id, categoryIds, promoIndex);
			return applied
				? {
					...p,
					discountedPrice: applied.finalUnitPrice,
					appliedPromotion: {
						id: applied.promotionId,
						name: applied.name,
						discountType: applied.discountType,
						discountValue: applied.discountValue
					}
				}
				: p;
		});

		const totalPages = Math.ceil(total / limit);

		// Redirect if page is out of bounds
		if (page > totalPages && total > 0) {
			const categoriesQuery = selectedCategories.length > 0 ? selectedCategories.join(',') : '';
			const searchQuery = search ? encodeURIComponent(search) : '';
			return redirect(
				302,
				`?page=${totalPages}&categories=${categoriesQuery}&year=${year}&limit=${limit}&search=${searchQuery}`
			);
		}

		return {
			// Cast so page component can access discountedPrice; original price retained in price field
			products: productsWithPricing as any,
			categories: categoryCounts,
			page,
			totalPages,
			totalResults: total,
			selectedCategories
		};
	} catch (e) {
		console.error('getPublishedProducts: ', e);
		return { status: 500, error: 'Internal server error getting published products' };
	}
}) satisfies PageServerLoad;
