/**
 * src/billing/cost-optimizer.ts
 * تحسين التكاليف الذكي — Smart cost optimization
 *
 * يقرر أي نموذج نستخدم بناءً على:
 * 1. نية الرسالة (intent)
 * 2. حالة الميزانية
 * 3. نوع الرسالة
 *
 * الهدف: أفضل جودة ممكنة ضمن الميزانية
 */
import { createChildLogger } from '../utils/logger.js';
import { supabase } from '../utils/supabase.js';
import { MODELS } from '../config.js';
import { walletManager } from './wallet.js';
const log = createChildLogger('billing:cost-optimizer');
// ─── سعر الصرف ──────────────────────────────────────────────────────
const SAR_TO_USD = 0.2667;
// ─── Model Selection Optimization ────────────────────────────────────
/**
 * تحسين اختيار النموذج بناءً على الميزانية والنية
 * يُستدعى قبل كل رسالة في brain.ts
 */
export async function optimizeModelSelection(tenantId, intent, messageType = 'text') {
    // تحديد المستوى الأصلي المطلوب بناءً على النية
    const originalTier = getDefaultTierForIntent(intent, messageType);
    // فحص حالة الميزانية
    const budgetStatus = await walletManager.getBudgetStatus(tenantId);
    // طلب التوصية من WalletManager
    const recommendation = await walletManager.getRecommendedTier(tenantId, intent, originalTier);
    // تقدير التكلفة المتوقعة
    const estimatedTokens = getEstimatedTokensForType(messageType, recommendation.tier);
    const estimatedCost = estimateMessageCost(getTierModel(recommendation.tier), estimatedTokens.input, estimatedTokens.output);
    // تسجيل قرار التحسين
    if (recommendation.downgraded) {
        log.info({
            tenantId,
            intent,
            originalTier,
            newTier: recommendation.tier,
            reason: recommendation.reason,
            budgetPercent: budgetStatus.percentUsed,
        }, 'Model downgraded for cost optimization');
    }
    return {
        recommendedTier: recommendation.tier,
        originalTier,
        downgraded: recommendation.downgraded,
        reason: recommendation.reason,
        budgetPercent: budgetStatus.percentUsed,
        estimatedCostUsd: estimatedCost,
    };
}
/**
 * تقدير تكلفة رسالة قبل إرسالها
 */
export function estimateMessageCost(model, estimatedTokensIn, estimatedTokensOut) {
    const costs = MODEL_COSTS[model];
    if (!costs)
        return 0;
    return ((estimatedTokensIn / 1_000_000) * costs.input +
        (estimatedTokensOut / 1_000_000) * costs.output);
}
/**
 * تقرير التكاليف اليومي لمستأجر
 */
export async function getDailyCostReport(tenantId, date) {
    const targetDate = date ?? new Date().toISOString().slice(0, 10);
    // تفصيل حسب النموذج
    const { data: modelRows } = await supabase
        .from('messages')
        .select('model, tokens_in, tokens_out, cost_usd, type')
        .eq('tenant_id', tenantId)
        .gte('created_at', `${targetDate}T00:00:00`)
        .lt('created_at', `${targetDate}T23:59:59.999`);
    const rows = modelRows ?? [];
    // تجميع حسب النموذج
    const modelMap = new Map();
    // تجميع حسب نوع الرسالة
    const typeMap = new Map();
    let totalCostUsd = 0;
    for (const row of rows) {
        const model = row.model ?? 'unknown';
        const cost = Number(row.cost_usd) || 0;
        totalCostUsd += cost;
        // حسب النموذج
        const modelEntry = modelMap.get(model) ?? { messagesCount: 0, tokensIn: 0, tokensOut: 0, costUsd: 0 };
        modelEntry.messagesCount++;
        modelEntry.tokensIn += row.tokens_in ?? 0;
        modelEntry.tokensOut += row.tokens_out ?? 0;
        modelEntry.costUsd += cost;
        modelMap.set(model, modelEntry);
        // حسب النوع
        const msgType = row.type ?? 'text';
        const typeEntry = typeMap.get(msgType) ?? { count: 0, costUsd: 0 };
        typeEntry.count++;
        typeEntry.costUsd += cost;
        typeMap.set(msgType, typeEntry);
    }
    return {
        date: targetDate,
        totalCostUsd: Math.round(totalCostUsd * 1000000) / 1000000,
        totalCostSar: Math.round((totalCostUsd / SAR_TO_USD) * 100) / 100,
        byModel: [...modelMap.entries()].map(([model, stats]) => ({
            model,
            ...stats,
            costUsd: Math.round(stats.costUsd * 1000000) / 1000000,
        })),
        byMessageType: [...typeMap.entries()].map(([type, stats]) => ({
            type,
            ...stats,
            costUsd: Math.round(stats.costUsd * 1000000) / 1000000,
        })),
    };
}
/**
 * مقارنة تكاليف النماذج — للوحة الإدارة
 */
export function getModelCostComparison() {
    // تقدير: رسالة متوسطة = 500 token input + 300 token output
    const avgInputTokens = 500;
    const avgOutputTokens = 300;
    return [
        {
            model: MODELS.router.model,
            tier: 'flash',
            costPer1MInput: MODELS.router.costPer1MInput,
            costPer1MOutput: MODELS.router.costPer1MOutput,
            avgCostPerMessage: estimateMessageCost(MODELS.router.model, avgInputTokens, avgOutputTokens),
            description: 'Gemini Flash — سريع ورخيص، للتصنيف والردود البسيطة',
        },
        {
            model: MODELS.brain.model,
            tier: 'brain',
            costPer1MInput: MODELS.brain.costPer1MInput,
            costPer1MOutput: MODELS.brain.costPer1MOutput,
            avgCostPerMessage: estimateMessageCost(MODELS.brain.model, avgInputTokens, avgOutputTokens),
            description: 'Qwen 72B — الدماغ الرئيسي، عربي ممتاز',
        },
        {
            model: MODELS.vision.model,
            tier: 'vision',
            costPer1MInput: MODELS.vision.costPer1MInput,
            costPer1MOutput: MODELS.vision.costPer1MOutput,
            avgCostPerMessage: estimateMessageCost(MODELS.vision.model, avgInputTokens, avgOutputTokens),
            description: 'Qwen VL — لمعالجة الصور والمستندات',
        },
        {
            model: MODELS.reasoning.model,
            tier: 'reasoning',
            costPer1MInput: MODELS.reasoning.costPer1MInput,
            costPer1MOutput: MODELS.reasoning.costPer1MOutput,
            avgCostPerMessage: estimateMessageCost(MODELS.reasoning.model, avgInputTokens, avgOutputTokens),
            description: 'DeepSeek R1 — تفكير عميق، للحالات المعقدة',
        },
    ];
}
// ─── Internal Helpers ────────────────────────────────────────────────
/**
 * تكاليف النماذج ($/1M tokens) — built at module load. Phase 1 collapses
 * multiple tiers onto the same model id (all NIM = $0); static literal keys
 * would error on duplicates.
 */
const MODEL_COSTS = (() => {
    const m = {};
    for (const tier of [MODELS.router, MODELS.brain, MODELS.vision, MODELS.reasoning]) {
        m[tier.model] = { input: tier.costPer1MInput, output: tier.costPer1MOutput };
    }
    return m;
})();
/** تحديد المستوى الافتراضي حسب النية */
function getDefaultTierForIntent(intent, messageType) {
    // الصور تحتاج vision → brain tier (نفس المزود)
    if (messageType === 'image')
        return 'brain';
    // التفكير العميق
    const reasoningIntents = ['complex_question', 'legal', 'financial_analysis', 'technical_deep'];
    if (reasoningIntents.includes(intent))
        return 'reasoning';
    // أغلب الأشياء تمر على brain
    const flashIntents = ['greeting', 'goodbye', 'thanks', 'faq_simple', 'hours', 'location'];
    if (flashIntents.includes(intent))
        return 'flash';
    return 'brain';
}
/** تقدير عدد التوكنات المتوقعة حسب نوع الرسالة والمستوى */
function getEstimatedTokensForType(messageType, tier) {
    // تقديرات تقريبية
    const estimates = {
        text: { input: 500, output: 300 },
        voice: { input: 600, output: 400 },
        image: { input: 1000, output: 400 },
        document: { input: 2000, output: 600 },
    };
    const base = estimates[messageType] ?? estimates['text'];
    // reasoning يستخدم توكنات أكثر
    if (tier === 'reasoning') {
        return { input: base.input * 1.5, output: base.output * 3 };
    }
    return base;
}
/** الحصول على اسم النموذج من المستوى */
function getTierModel(tier) {
    switch (tier) {
        case 'flash': return MODELS.router.model;
        case 'brain': return MODELS.brain.model;
        case 'reasoning': return MODELS.reasoning.model;
        default: return MODELS.brain.model;
    }
}
//# sourceMappingURL=cost-optimizer.js.map