import { and, eq, sql } from "drizzle-orm";
import type { db as prodDb } from "../../db/index.ts";
import {
	categories,
	globalItems,
	items,
	setupItems,
	setups,
	users,
} from "../../db/schema.ts";
import type { UpdateProfile } from "../../shared/types.ts";

type Db = typeof prodDb;

export async function updateProfile(
	db: Db,
	userId: number,
	data: UpdateProfile,
) {
	const [existing] = await db.select().from(users).where(eq(users.id, userId));
	if (!existing) return null;

	// If no fields to update, return existing user
	const hasUpdates = Object.values(data).some((v) => v !== undefined);
	if (!hasUpdates) return existing;

	const [updated] = await db
		.update(users)
		.set(data)
		.where(eq(users.id, userId))
		.returning();

	return updated;
}

export async function getPublicProfile(db: Db, userId: number) {
	const [user] = await db
		.select({
			id: users.id,
			displayName: users.displayName,
			avatarUrl: users.avatarUrl,
			bio: users.bio,
		})
		.from(users)
		.where(eq(users.id, userId));

	if (!user) return null;

	const publicSetups = await db
		.select({
			id: setups.id,
			name: setups.name,
			createdAt: setups.createdAt,
			itemCount: sql<number>`COALESCE((
				SELECT COUNT(*) FROM setup_items
				WHERE setup_items.setup_id = setups.id
			), 0)`.as("item_count"),
			totalWeight: sql<number>`COALESCE((
				SELECT SUM(
					COALESCE(
						CASE WHEN items.global_item_id IS NOT NULL THEN global_items.weight_grams ELSE NULL END,
						items.weight_grams
					) * items.quantity
				) FROM setup_items
				JOIN items ON items.id = setup_items.item_id
				LEFT JOIN global_items ON global_items.id = items.global_item_id
				WHERE setup_items.setup_id = setups.id
			), 0)`.as("total_weight"),
			totalCost: sql<number>`COALESCE((
				SELECT SUM(
					COALESCE(
						CASE WHEN items.global_item_id IS NOT NULL THEN global_items.price_cents ELSE NULL END,
						items.price_cents
					) * items.quantity
				) FROM setup_items
				JOIN items ON items.id = setup_items.item_id
				LEFT JOIN global_items ON global_items.id = items.global_item_id
				WHERE setup_items.setup_id = setups.id
			), 0)`.as("total_cost"),
		})
		.from(setups)
		.where(and(eq(setups.userId, userId), eq(setups.visibility, "public")));

	return { ...user, setups: publicSetups };
}

export async function getPublicSetupWithItems(db: Db, setupId: number) {
	const [setup] = await db
		.select()
		.from(setups)
		.where(and(eq(setups.id, setupId), eq(setups.visibility, "public")));

	if (!setup) return null;

	const itemList = await db
		.select({
			id: items.id,
			name: sql<string>`COALESCE(
				CASE WHEN ${items.globalItemId} IS NOT NULL
					THEN ${globalItems.brand} || ' ' || ${globalItems.model}
					ELSE ${items.name}
				END,
				${items.name}
			)`.as("name"),
			weightGrams: sql<number | null>`COALESCE(
				CASE WHEN ${items.globalItemId} IS NOT NULL THEN ${globalItems.weightGrams} ELSE NULL END,
				${items.weightGrams}
			)`.as("weight_grams"),
			priceCents: sql<number | null>`COALESCE(
				CASE WHEN ${items.globalItemId} IS NOT NULL THEN ${globalItems.priceCents} ELSE NULL END,
				${items.priceCents}
			)`.as("price_cents"),
			quantity: items.quantity,
			categoryId: items.categoryId,
			notes: items.notes,
			productUrl: items.productUrl,
			imageFilename: sql<string | null>`COALESCE(
				${items.imageFilename},
				CASE WHEN ${items.globalItemId} IS NOT NULL THEN ${globalItems.imageUrl} ELSE NULL END
			)`.as("image_filename"),
			globalItemId: items.globalItemId,
			createdAt: items.createdAt,
			updatedAt: items.updatedAt,
			categoryName: categories.name,
			categoryIcon: categories.icon,
			classification: setupItems.classification,
		})
		.from(setupItems)
		.innerJoin(items, eq(setupItems.itemId, items.id))
		.innerJoin(categories, eq(items.categoryId, categories.id))
		.leftJoin(globalItems, eq(items.globalItemId, globalItems.id))
		.where(eq(setupItems.setupId, setupId));

	return { ...setup, items: itemList };
}
