const mongoose = require('mongoose') const timestamp = require('mongoose-timestamp') const mongoosePaginate = require('mongoose-paginate-v2') // تبلیغِ کاربری — نوعش تعیین می‌کنه محتواش کجا تزریق می‌شه: first_post (اول فید)، // first_story (اول نوار استوری)، notification (پوش مستقیم به کاربرهای هدف)، project/ // product/shop/billboard (اول لیستِ مربوطه، از utils/adDelivery.js:findActiveAd با همون // ad_type resolve می‌شه). هدف‌گذاری (لوکیشن/تخصص/جنسیت) روی همون فیلدهایی که // User/Post/exploreAlgorithm.js از قبل استفاده می‌کنن سوار شده (province.id عددیه، نه // ObjectId — utils/adPricing.js همین رو resolve می‌کنه) const AD_TYPES = ['first_post', 'first_story', 'notification', 'project', 'product', 'shop', 'billboard'] const adSchema = new mongoose.Schema({ user_id: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true }, ad_type: { type: String, enum: AD_TYPES, required: true }, // محتوا — بسته به ad_type فقط یکی از این پر می‌شه content_post_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Post', default: null }, content_project_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Project', default: null }, content_shop_product_id: { type: mongoose.Schema.Types.ObjectId, ref: 'ShopProductListing', default: null }, content_shop_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Shop', default: null }, content_billboard_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Advertising', default: null }, // استوری‌های واقعی معمولاً ۲۴ساعته منقضی می‌شن (StoryModel: expires_at) و از فیدِ // استوریِ معمولی حذف می‌شن، ولی یه کمپینِ تبلیغاتی می‌تونه چند روز فعال بمونه — پس // مدیا/اورلی‌ها رو موقعِ ساختِ تبلیغ اینجا کپی/اسنپ‌شات می‌کنیم تا مستقل از عمرِ // طبیعیِ خودِ استوری باشه (content_story_id فقط برای رفرنسِ منبع نگه داشته می‌شه) content_story_id: { type: mongoose.Schema.Types.ObjectId, ref: 'Story', default: null }, content_media_path: { type: String, default: null }, content_media_type: { type: String, default: null }, content_overlays: { type: mongoose.Schema.Types.Mixed, default: null }, notification_title: { type: String, trim: true, default: null }, notification_body: { type: String, trim: true, default: null }, // هدف‌گذاری target_country_id: { type: Number, default: null }, target_province_id: { type: Number, default: null }, target_city_id: { type: Number, default: null }, target_expertise: { type: String, trim: true, default: null }, target_sub_expertise: { type: [String], default: [] }, target_gender: { type: String, enum: ['female', 'male', 'any'], default: 'any' }, // مالی price: { type: Number, required: true }, walletAmountUsed: { type: Number, default: 0 }, payment_authority: { type: String, default: null }, status: { type: String, enum: ['pending_payment', 'active', 'expired', 'failed'], default: 'pending_payment' }, started_at: { type: Date, default: null }, // عین بقیه‌ی کمپین‌های اپ، یه مدت‌زمانِ ثابت (AD_CAMPAIGN_DURATION_DAYS توی // adsController.js) بعد از فعال‌شدن — بعدش دیگه توی تزریقِ فید/استوری/نوتیف لحاظ نمی‌شه expires_at: { type: Date, default: null }, views_count: { type: Number, default: 0 }, clicks_count: { type: Number, default: 0 } }) // تزریق (سرچِ یه تبلیغِ فعالِ منطبق روی فید/استوری) و لیستِ «تبلیغ‌های من» دو مصرفِ // اصلیِ ایندکسن adSchema.index({ status: 1, ad_type: 1, expires_at: 1 }) adSchema.index({ user_id: 1, createdAt: -1 }) adSchema.plugin(timestamp) adSchema.plugin(mongoosePaginate) const AdModel = mongoose.model('Ad', adSchema) // روی خودِ مدل به‌عنوان استاتیک — تا adsController.js/adsPanelController.js بدونِ // require جدا به لیستِ معتبرِ ad_type دسترسی داشته باشن (module.exports همون مدله، نه یه آبجکت) AdModel.AD_TYPES = AD_TYPES module.exports = AdModel