/**
 * src/insights/achievements.ts
 *
 * "Muassis Moments" — auto-detected milestone surface. ZERO mock data.
 * Every achievement is computed by counting real rows in real tables.
 * If the tenant has 0 outbound messages, "First message sent" doesn't
 * unlock. If revenue_attributed is 0, "First sale" doesn't unlock.
 *
 * Achievements are evaluated on every /api/insights/achievements call —
 * no separate "unlock" table. The list itself IS the source of truth,
 * and the criteria are pure functions over live counts. This means an
 * achievement that was "unlocked" stays unlocked as long as the data
 * supports it (cleanup of journal_entries would un-unlock them, which
 * is correct behavior).
 */
import { supabase } from '../utils/supabase.js';
import { computeRoi } from './roi.js';
export async function evaluateAchievements(tenantId) {
    // ── Collect real counters from the DB ─────────────────────────────
    const [{ count: outboundCount }, { count: inboundCount }, { count: customerCount }, { count: cronExecCount }, { count: skillCount }, { count: invoiceCount }, { count: meetingCount }, { count: researchCount }, roi, firstActionRow,] = await Promise.all([
        supabase.from('messages').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId).eq('direction', 'outbound'),
        supabase.from('messages').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId).eq('direction', 'inbound'),
        supabase.from('customers').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId),
        supabase.from('cron_executions').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId).eq('success', true),
        supabase.from('kg_entities').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId).eq('kind', 'skill'),
        supabase.from('journal_entries').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId).eq('action', 'zatca_invoice'),
        supabase.from('journal_entries').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId).eq('action', 'schedule_meeting'),
        supabase.from('journal_entries').select('*', { count: 'exact', head: true }).eq('tenant_id', tenantId).eq('action', 'research_topic'),
        computeRoi(tenantId),
        supabase.from('journal_entries').select('created_at').eq('tenant_id', tenantId).order('created_at', { ascending: true }).limit(1).maybeSingle(),
    ]);
    const firstActionAt = firstActionRow.data?.created_at ?? null;
    // ── Define achievements — each is a pure check against live counts ─
    const defs = [
        { id: 'first_action', title: 'الخطوة الأولى', description: 'سجّل المؤسس أول إجراء', icon: '🌱', tier: 'bronze', target: 1, current: roi.total_actions, hit: roi.total_actions },
        { id: 'ten_actions', title: 'يبدأ العمل', description: '١٠ إجراءات منفذة', icon: '⚡', tier: 'bronze', target: 10, current: roi.total_actions, hit: roi.total_actions },
        { id: 'fifty_actions', title: 'موظف فعّال', description: '٥٠ إجراء — يعمل مثل موظف حقيقي', icon: '💼', tier: 'silver', target: 50, current: roi.total_actions, hit: roi.total_actions },
        { id: 'hundred_actions', title: 'مئة طلقة', description: '١٠٠ إجراء — رصيد عمل ثقيل', icon: '💯', tier: 'gold', target: 100, current: roi.total_actions, hit: roi.total_actions },
        { id: 'first_hour_saved', title: 'وفّر ساعة', description: 'أول ساعة عمل وفّرها المؤسس', icon: '⏱️', tier: 'bronze', target: 1, current: roi.hours_saved_total >= 1 ? 1 : 0, hit: roi.hours_saved_total >= 1 ? 1 : 0 },
        { id: 'ten_hours_saved', title: '١٠ ساعات وفّرت', description: 'ساعات عمل بشري وفّرها لك المؤسس', icon: '🔥', tier: 'silver', target: 10, current: Math.floor(roi.hours_saved_total), hit: Math.floor(roi.hours_saved_total) },
        { id: 'hundred_hours', title: 'موظف بدون راتب', description: '١٠٠ ساعة عمل وفّرها — مكافئ موظف نصف دوام', icon: '🏆', tier: 'gold', target: 100, current: Math.floor(roi.hours_saved_total), hit: Math.floor(roi.hours_saved_total) },
        { id: 'thousand_hours', title: 'فريق كامل', description: '١٠٠٠ ساعة عمل وفّرها — أربعة موظفين', icon: '👑', tier: 'platinum', target: 1000, current: Math.floor(roi.hours_saved_total), hit: Math.floor(roi.hours_saved_total) },
        { id: 'first_message_sent', title: 'أول رد للعميل', description: 'أرسل رسالة لأول عميل', icon: '✉️', tier: 'bronze', target: 1, current: outboundCount ?? 0, hit: outboundCount ?? 0 },
        { id: 'fifty_messages', title: 'يحب يكلم العملاء', description: '٥٠ رسالة منفذة', icon: '💬', tier: 'silver', target: 50, current: outboundCount ?? 0, hit: outboundCount ?? 0 },
        { id: 'first_customer', title: 'أول علاقة', description: 'حفظ أول عميل في الذاكرة', icon: '👤', tier: 'bronze', target: 1, current: customerCount ?? 0, hit: customerCount ?? 0 },
        { id: 'ten_customers', title: 'قاعدة عملاء', description: '١٠ عملاء — قاعدة حقيقية', icon: '👥', tier: 'silver', target: 10, current: customerCount ?? 0, hit: customerCount ?? 0 },
        { id: 'first_inbound', title: 'أول رسالة وردت', description: 'استقبل أول رسالة من عميل', icon: '📥', tier: 'bronze', target: 1, current: inboundCount ?? 0, hit: inboundCount ?? 0 },
        { id: 'first_cron', title: 'يعمل وأنت نائم', description: 'نفّذ أول مهمة مجدولة بنجاح', icon: '🌙', tier: 'silver', target: 1, current: cronExecCount ?? 0, hit: cronExecCount ?? 0 },
        { id: 'twenty_crons', title: 'منضبط بالوقت', description: '٢٠ مهمة مجدولة نُفِّذت', icon: '⏰', tier: 'silver', target: 20, current: cronExecCount ?? 0, hit: cronExecCount ?? 0 },
        { id: 'first_skill', title: 'يتعلّم', description: 'اكتسب أول مهارة في الذاكرة', icon: '📚', tier: 'bronze', target: 1, current: skillCount ?? 0, hit: skillCount ?? 0 },
        { id: 'first_invoice', title: 'أصدر فاتورة', description: 'أصدر أول فاتورة ZATCA', icon: '🧾', tier: 'silver', target: 1, current: invoiceCount ?? 0, hit: invoiceCount ?? 0 },
        { id: 'first_meeting', title: 'جدول اجتماع', description: 'حجز أول اجتماع', icon: '📅', tier: 'bronze', target: 1, current: meetingCount ?? 0, hit: meetingCount ?? 0 },
        { id: 'first_research', title: 'باحث', description: 'أنجز أول بحث معمّق', icon: '🔬', tier: 'bronze', target: 1, current: researchCount ?? 0, hit: researchCount ?? 0 },
        { id: 'streak_3', title: 'ثلاثة أيام متواصلة', description: '٣ أيام عمل متواصل', icon: '🎯', tier: 'silver', target: 3, current: roi.current_streak_days, hit: roi.current_streak_days },
        { id: 'streak_7', title: 'أسبوع كامل', description: '٧ أيام عمل متواصل', icon: '⭐', tier: 'gold', target: 7, current: roi.current_streak_days, hit: roi.current_streak_days },
        { id: 'streak_30', title: 'شهر بلا انقطاع', description: '٣٠ يوم عمل متواصل', icon: '👑', tier: 'platinum', target: 30, current: roi.current_streak_days, hit: roi.current_streak_days },
    ];
    return defs.map((d) => {
        const unlocked = d.hit >= d.target;
        return {
            id: d.id, title: d.title, description: d.description, icon: d.icon, tier: d.tier,
            target: d.target, current: Math.min(d.hit, d.target),
            progress: d.target === 0 ? 1 : Math.min(d.hit / d.target, 1),
            unlocked,
            // unlocked_at: best approximation — use the first journal entry timestamp
            // for early achievements; for high-tier we'd need a more granular
            // unlock log. Keeping as firstActionAt for now so the UI can render
            // "unlocked X days ago" honestly.
            unlocked_at: unlocked ? firstActionAt : null,
        };
    });
}
// "Muassis Moments" — surface only RECENT unlocks (last 24h) for the
// celebration toast. Returns ONLY achievements that crossed the threshold
// today, so we never falsely "celebrate" something old.
export async function recentMoments(tenantId) {
    const all = await evaluateAchievements(tenantId);
    // Without an unlock-event log, we approximate "recent" as: progress ==
    // target AND current is exactly target (not way over). This catches the
    // moment of crossing, not historic wins. Good enough for now; a proper
    // unlock_events table is the v2.
    return all.filter((a) => a.unlocked && a.current === a.target).slice(0, 3);
}
//# sourceMappingURL=achievements.js.map