import { a as encodeCursor, i as decodeCursor } from "./types-CuW0zWDA.mjs";
import { n as chunks, t as SQL_BATCH_SIZE } from "./chunks-B2isWQhr.mjs";
import { ulid } from "ulidx";

//#region src/database/repositories/user.ts
/**
* User repository for CRUD operations
*/
var UserRepository = class UserRepository {
	constructor(db) {
		this.db = db;
	}
	/**
	* Create a new user
	*/
	async create(input) {
		const id = ulid();
		const row = {
			id,
			email: input.email.toLowerCase(),
			name: input.name ?? null,
			role: UserRepository.resolveRole(input.role ?? 10),
			avatar_url: input.avatarUrl ?? null,
			email_verified: 0,
			data: input.data ? JSON.stringify(input.data) : null
		};
		await this.db.insertInto("users").values(row).execute();
		const user = await this.findById(id);
		if (!user) throw new Error("Failed to create user");
		return user;
	}
	/**
	* Find user by ID
	*/
	async findById(id) {
		const row = await this.db.selectFrom("users").selectAll().where("id", "=", id).executeTakeFirst();
		return row ? this.rowToUser(row) : null;
	}
	/**
	* Batch-resolve users by ID. Returns only the users that exist; missing
	* IDs are silently dropped. Chunked at `SQL_BATCH_SIZE` to stay within
	* D1's bind-parameter limit.
	*/
	async findByIds(ids) {
		const unique = [...new Set(ids)].filter((id) => id.length > 0);
		if (unique.length === 0) return [];
		const out = [];
		for (const batch of chunks(unique, SQL_BATCH_SIZE)) {
			const rows = await this.db.selectFrom("users").selectAll().where("id", "in", batch).execute();
			for (const row of rows) out.push(this.rowToUser(row));
		}
		return out;
	}
	/**
	* Find user by email (case-insensitive)
	*/
	async findByEmail(email) {
		const row = await this.db.selectFrom("users").selectAll().where("email", "=", email.toLowerCase()).executeTakeFirst();
		return row ? this.rowToUser(row) : null;
	}
	/**
	* List all users with cursor-based pagination
	*/
	async findMany(options = {}) {
		const limit = Math.min(Math.max(1, options.limit || 50), 100);
		let query = this.db.selectFrom("users").selectAll().orderBy("created_at", "desc").orderBy("id", "desc").limit(limit + 1);
		if (options.role !== void 0) query = query.where("role", "=", UserRepository.resolveRole(options.role));
		if (options.cursor) {
			const decoded = decodeCursor(options.cursor);
			query = query.where((eb) => eb.or([eb("created_at", "<", decoded.orderValue), eb.and([eb("created_at", "=", decoded.orderValue), eb("id", "<", decoded.id)])]));
		}
		const rows = await query.execute();
		const items = rows.slice(0, limit).map((row) => this.rowToUser(row));
		const result = { items };
		if (rows.length > limit && items.length > 0) {
			const last = items.at(-1);
			result.nextCursor = encodeCursor(last.createdAt, last.id);
		}
		return result;
	}
	/**
	* Update a user
	*/
	async update(id, input) {
		if (!await this.findById(id)) return null;
		const updates = {};
		if (input.name !== void 0) updates.name = input.name;
		if (input.role !== void 0) updates.role = UserRepository.resolveRole(input.role);
		if (input.avatarUrl !== void 0) updates.avatar_url = input.avatarUrl;
		if (input.data !== void 0) updates.data = JSON.stringify(input.data);
		if (Object.keys(updates).length > 0) await this.db.updateTable("users").set(updates).where("id", "=", id).execute();
		return this.findById(id);
	}
	/**
	* Delete a user
	*/
	async delete(id) {
		return ((await this.db.deleteFrom("users").where("id", "=", id).executeTakeFirst()).numDeletedRows ?? 0) > 0;
	}
	/**
	* Count users
	*/
	async count(role) {
		let query = this.db.selectFrom("users").select((eb) => eb.fn.count("id").as("count"));
		if (role !== void 0) query = query.where("role", "=", UserRepository.resolveRole(role));
		const result = await query.executeTakeFirst();
		return Number(result?.count || 0);
	}
	/**
	* Check if email exists
	*/
	async emailExists(email) {
		return !!await this.db.selectFrom("users").select("id").where("email", "=", email.toLowerCase()).executeTakeFirst();
	}
	/**
	* Convert database row to User object
	*/
	rowToUser(row) {
		return {
			id: row.id,
			email: row.email,
			name: row.name,
			role: UserRepository.toRole(row.role),
			avatarUrl: row.avatar_url,
			emailVerified: row.email_verified === 1,
			data: row.data ? JSON.parse(row.data) : null,
			createdAt: row.created_at
		};
	}
	/** Map of role name strings to numeric levels */
	static ROLE_NAME_TO_LEVEL = {
		subscriber: 10,
		contributor: 20,
		author: 30,
		editor: 40,
		admin: 50
	};
	/** Valid numeric role levels */
	static VALID_LEVELS = new Set([
		10,
		20,
		30,
		40,
		50
	]);
	/**
	* Resolve a role name or number to a valid numeric UserRole.
	* Accepts both string names ("admin") and numeric levels (50).
	*/
	static resolveRole(role) {
		if (typeof role === "string") {
			const level = UserRepository.ROLE_NAME_TO_LEVEL[role];
			if (level === void 0) throw new Error(`Invalid role name: ${role}`);
			return level;
		}
		if (!UserRepository.VALID_LEVELS.has(role)) throw new Error(`Invalid role level: ${role}`);
		return role;
	}
	/**
	* Convert a raw DB integer to a typed UserRole.
	* Falls back to subscriber (10) for unknown values.
	*/
	static toRole(level) {
		if (UserRepository.VALID_LEVELS.has(level)) return level;
		return 10;
	}
};

//#endregion
export { UserRepository as t };
//# sourceMappingURL=user-BjAOvU3Z.mjs.map