import { API_CLIENT_ID, KEY, SECRET, SERVICE_ID } from '$env/static/private';
import type { PageServerLoad } from './$types';
import { redirect } from '@sveltejs/kit';
import { createHmac } from 'node:crypto';
import prisma from '$lib/server/prisma';
import {
	buildPromotionIndex,
	getActivePromotions,
	selectBestPromotionIndexed
} from '$lib/server/promotionPricing';

export const load = (async ({ locals: { user }, url: { origin }, depends }) => {
	if (!user) redirect(302, '/login');
	depends('update:paymentDetails'); // TODO: check if this is necessary
	try {
		const cart = await prisma.cart.findUnique({
			where: {
				userId: user.id
			},
			include: {
				// Reason: We need product categories to evaluate category-based promotions on checkout
				CartItem: { include: { product: { include: { categories: { select: { id: true } } } } } },
				user: { select: { name: true, email: true, phoneNumber: true, idNumber: true } }
			}
		});
		if (!cart) {
			console.error('Cart not found');
			return { error: 'Cart not found' };
		}
		const convenienceFee = (await prisma.convenienceFee.findFirst()) || { amount: 0 };

		// Calculate total price (promotion-aware)
		// Reason: Ensure the amount sent to the payment provider reflects active promotions applied to products/categories.
		const productIds = cart.CartItem.map((ci) => ci.product.id);
		const categoryIds = Array.from(
			new Set(
				cart.CartItem.flatMap((ci) => (ci.product.categories || []).map((c: { id: number }) => c.id))
			)
		);
		const activePromos = await getActivePromotions(new Date(), { productIds, categoryIds });
		const promoIndex = buildPromotionIndex(activePromos);
		const discountedSubtotal = cart.CartItem.reduce((total, item) => {
			const base = item.product.price;
			const cats = (item.product.categories || []).map((c: { id: number }) => c.id);
			const applied = selectBestPromotionIndexed(base, item.product.id, cats, promoIndex);
			const unit = applied?.finalUnitPrice ?? base;
			return total + unit * item.quantity;
		}, 0);
		// Normalize to 2dp to match UI/cart math and avoid floating point drift
		const totalPrice = Number((discountedSubtotal).toFixed(2));

		const billRefNumber = `ORDER-${Date.now()}`;

		// Update cart with payment reference
		await prisma.cart.update({
			where: { userId: user.id },
			data: {
				paymentReference: billRefNumber,
				status: 'PENDING_PAYMENT'
			}
		});

		// Prepare payment details
		const paymentDetails = {
			apiClientID: API_CLIENT_ID, // Your Pesaflow API Client ID
			amountExpected: Number((totalPrice + convenienceFee.amount).toFixed(2)),
			serviceID: SERVICE_ID,
			clientIDNumber: cart.user.idNumber || '0',
			currency: 'KES',
			billRefNumber,
			billDesc: 'Product Purchase',
			clientName: cart.user.name || cart.user.email,
			secret: SECRET
		};

		// Data string for secure hash
		const dataString = [
			paymentDetails.apiClientID,
			paymentDetails.amountExpected,
			paymentDetails.serviceID,
			paymentDetails.clientIDNumber,
			paymentDetails.currency,
			paymentDetails.billRefNumber,
			paymentDetails.billDesc,
			paymentDetails.clientName,
			paymentDetails.secret
		].join('');


		// Generate secure hash
		const secureHash = generateSecureHash(dataString, KEY);

		return {
			paymentDetails: {
				...paymentDetails,
				secureHash,
				callBackURLOnSuccess: `${origin}/checkout`,
				callBackURLOnFail: `${origin}/checkout`,
				notificationURL: `${origin}/api/order/notification_url`,
				clientEmail: cart.user.email,
				clientMSISDN: cart.user.phoneNumber || '0700000000',
				pictureURL: `${origin}/kLawLogo.png`
			},
			convenienceFee
		};
	} catch (e) {
		console.error(e);
		return { error: 'Internal Error loading checkout page' };
	}
}) satisfies PageServerLoad;


/**
 * Generate a secure hash using HMAC with SHA256
 * @param dataString String to hash
 * @param secretKey Secret key to use for hashing
 * @returns Base64 encoded hash
 */
function generateSecureHash(dataString: string, secretKey: string): string {
	// Create HMAC with SHA256
	const hmac = createHmac('sha256', secretKey);
	// Update with data and generate hash
	hmac.update(dataString);

	// Generate base64 encoded hash
	return hmac.digest('base64');
}