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

type Db = typeof prodDb;

export async function getAllItems(db: Db, userId: number) {
	return 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"),
			purchasePriceCents: items.purchasePriceCents,
			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"),
			imageSourceUrl: items.imageSourceUrl,
			globalItemId: items.globalItemId,
			brand: sql<
				string | null
			>`COALESCE(${globalItems.brand}, ${items.brand})`.as("brand"),
			dominantColor: items.dominantColor,
			cropZoom: items.cropZoom,
			cropX: items.cropX,
			cropY: items.cropY,
			createdAt: items.createdAt,
			updatedAt: items.updatedAt,
			categoryName: categories.name,
			categoryIcon: categories.icon,
		})
		.from(items)
		.innerJoin(categories, eq(items.categoryId, categories.id))
		.leftJoin(globalItems, eq(items.globalItemId, globalItems.id))
		.where(eq(items.userId, userId));
}

export async function getItemById(db: Db, userId: number, id: number) {
	const [row] = 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"),
			purchasePriceCents: items.purchasePriceCents,
			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"),
			imageSourceUrl: items.imageSourceUrl,
			globalItemId: items.globalItemId,
			brand: sql<
				string | null
			>`COALESCE(${globalItems.brand}, ${items.brand})`.as("brand"),
			dominantColor: items.dominantColor,
			cropZoom: items.cropZoom,
			cropX: items.cropX,
			cropY: items.cropY,
			createdAt: items.createdAt,
			updatedAt: items.updatedAt,
			categoryName: categories.name,
			categoryIcon: categories.icon,
		})
		.from(items)
		.innerJoin(categories, eq(items.categoryId, categories.id))
		.leftJoin(globalItems, eq(items.globalItemId, globalItems.id))
		.where(and(eq(items.id, id), eq(items.userId, userId)));

	return row ?? null;
}

export async function createItem(
	db: Db,
	userId: number,
	data: Partial<CreateItem> & {
		name: string;
		categoryId: number;
		imageFilename?: string;
	},
) {
	// For reference items, look up global item for fallback name (items.name is NOT NULL)
	let name = data.name;
	if (data.globalItemId) {
		const [gi] = await db
			.select({ brand: globalItems.brand, model: globalItems.model })
			.from(globalItems)
			.where(eq(globalItems.id, data.globalItemId));
		if (gi) {
			name = `${gi.brand} ${gi.model}`;
		}
	}

	const [row] = await db
		.insert(items)
		.values({
			name,
			weightGrams: data.weightGrams ?? null,
			priceCents: data.priceCents ?? null,
			quantity: data.quantity ?? 1,
			categoryId: data.categoryId,
			userId,
			notes: data.notes ?? null,
			productUrl: data.productUrl ?? null,
			imageFilename: data.imageFilename ?? null,
			imageSourceUrl: data.imageSourceUrl ?? null,
			globalItemId: data.globalItemId ?? null,
			purchasePriceCents: data.purchasePriceCents ?? null,
		})
		.returning();

	return row;
}

export async function updateItem(
	db: Db,
	userId: number,
	id: number,
	data: Partial<{
		name: string;
		weightGrams: number;
		priceCents: number;
		quantity: number;
		categoryId: number;
		notes: string;
		productUrl: string;
		imageFilename: string;
		imageSourceUrl: string;
		globalItemId: number;
		purchasePriceCents: number;
		brand: string;
		dominantColor: string | null;
		cropZoom: number | null;
		cropX: number | null;
		cropY: number | null;
	}>,
) {
	// Check if item exists and belongs to user
	const [existing] = await db
		.select({ id: items.id })
		.from(items)
		.where(and(eq(items.id, id), eq(items.userId, userId)));

	if (!existing) return null;

	const [row] = await db
		.update(items)
		.set({ ...data, updatedAt: new Date() })
		.where(and(eq(items.id, id), eq(items.userId, userId)))
		.returning();

	return row;
}

export async function duplicateItem(db: Db, userId: number, id: number) {
	const [source] = await db
		.select()
		.from(items)
		.where(and(eq(items.id, id), eq(items.userId, userId)));

	if (!source) return null;

	const [row] = await db
		.insert(items)
		.values({
			name: `${source.name} (copy)`,
			weightGrams: source.weightGrams,
			priceCents: source.priceCents,
			categoryId: source.categoryId,
			userId,
			notes: source.notes,
			productUrl: source.productUrl,
			imageFilename: source.imageFilename,
			imageSourceUrl: source.imageSourceUrl,
			quantity: source.quantity,
			globalItemId: source.globalItemId,
			purchasePriceCents: source.purchasePriceCents,
		})
		.returning();

	return row;
}

export async function deleteItem(db: Db, userId: number, id: number) {
	// Get item first (for image cleanup info)
	const [item] = await db
		.select()
		.from(items)
		.where(and(eq(items.id, id), eq(items.userId, userId)));

	if (!item) return null;

	await db.delete(items).where(and(eq(items.id, id), eq(items.userId, userId)));

	return item;
}
