import mongoose, { Document, Model } from 'mongoose' import { z } from 'zod' import bcrypt from 'bcryptjs' // Zod schema for validation export const UserSchema = z.object({ email: z.string().email('Invalid email format'), name: z.string().min(1, 'Name is required'), password: z.string().min(6, 'Password must be at least 6 characters'), siliconId: z.string().optional(), role: z.enum(['user', 'admin']).optional().default('user'), isVerified: z.boolean().optional().default(false), provider: z.string().optional(), providerId: z.string().optional(), avatar: z.string().url().optional(), }) export type UserType = z.infer // Mongoose interface export interface IUser extends Document { email: string name: string password?: string siliconId: string role: 'user' | 'admin' isVerified: boolean provider: 'local' | 'google' | 'github' providerId?: string avatar?: string refreshToken?: string balance?: number lastLogin: Date createdAt: Date updatedAt: Date comparePassword(candidatePassword: string): Promise } // Mongoose schema const userSchema = new mongoose.Schema( { email: { type: String, required: true, lowercase: true, trim: true, }, name: { type: String, required: true, trim: true, }, siliconId: { type: String, required: true, trim: true, }, password: { type: String, required: function (this: any) { return !this.provider // Password required only if not using OAuth }, }, role: { type: String, enum: ['user', 'admin'], default: 'user', }, balance: { type: Number, default: 0, min: 0, }, isVerified: { type: Boolean, default: false, }, provider: { type: String, enum: ['local', 'google', 'github'], default: 'local', }, providerId: String, avatar: String, refreshToken: String, lastLogin: { type: Date, default: Date.now, }, }, { timestamps: true, } ) // Index for performance userSchema.index({ email: 1 }, { unique: true }) userSchema.index({ siliconId: 1 }, { unique: true }) userSchema.index({ providerId: 1, provider: 1 }) // Hash password before saving userSchema.pre('save', async function (next) { if (!this.isModified('password')) return next() if (this.password) { this.password = await bcrypt.hash(this.password, 12) } next() }) // Compare password method userSchema.methods.comparePassword = async function (candidatePassword: string): Promise { if (!this.password) return false return bcrypt.compare(candidatePassword, this.password) } // Transform method to remove sensitive fields userSchema.methods.toJSON = function () { const user = this.toObject() delete user.password delete user.refreshToken return user } export const User: Model = mongoose.models.User || mongoose.model('User', userSchema)