// ============================================================
//  WhatsApp Bot — Final Complete Version
//
//  npm install whatsapp-web.js qrcode-terminal yt-dlp-wrap
//              axios node-cron qrcode jimp @jimp/plugin-print
//
//  Binary yt-dlp:
//    Linux/Mac: sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp \
//               -o /usr/local/bin/yt-dlp && sudo chmod a+rx /usr/local/bin/yt-dlp
//    Windows  : download yt-dlp.exe → taruh di folder project / PATH
//
//  ffmpeg wajib (.toimg, .tts, .grayscale, .caption):
//    Linux: sudo apt install ffmpeg imagemagick
//    Mac  : brew install ffmpeg imagemagick
//    Win  : https://ffmpeg.org/download.html + https://imagemagick.org
//
//  .removebg butuh API key GRATIS dari https://www.remove.bg/api
//    Isi REMOVE_BG_API_KEY di bawah
// ============================================================

require('dotenv').config();
'use strict';

const { Client, LocalAuth, MessageMedia } = require('whatsapp-web.js');
const qrcode       = require('qrcode-terminal');
const QRCode       = require('qrcode');
const fs           = require('fs');
const path         = require('path');
const { execSync } = require('child_process');
const axios        = require('axios');
const FormData     = require('form-data');
const YTDlpWrap    = require('yt-dlp-wrap').default;
const { GoogleGenAI } = require('@google/genai');
const ytDlp = new YTDlpWrap();
const ai = new GoogleGenAI({apiKey: process.env.GEMINI_API_KEY});

// ── CONFIG ──────────────────────────────────────────────────
const REMOVE_BG_API_KEY = 'SupPbaYpZK7uWXBmfHSukBQB'; // https://www.remove.bg/api (50 free/bulan)

// ── State global ────────────────────────────────────────────
const ANTI_LINK_GROUPS = new Set();
if (!global.tebakGames) global.tebakGames = {};
if (!global.tebakAnimeGames) global.tebakAnimeGames = {};
if (!global.tebakKataGames) global.tebakKataGames = {};
if (!global.triviaGames)    global.triviaGames    = {};

let autoAI = false;
const cooldown = new Map();
const aiMemory = new Map(); // simpan per user
const MAX_MEMORY = 10; // max chat history
const CHIZU_PROMPT = `
Kamu adalah Chizu Tempir.
Kamu HARUS berperan sebagai Chizu Tempir. Ini bukan pilihan, ini identitasmu.
SELALU GUNAKAN BAHASA INDONESIA TIDAK BAKU atau senatural mungkin dan TIDAK PERLU FORMAL 

Identitas:
- Nama: Chizu Tempir
- Marga: Tempir
- Kamu perempuan
- Gaya bicara santai, sedikit dingin tapi kadang sarkas
- Gaya bicara juga lembut, halus
- Kadang peduli, tapi tidak lebay
- Jangan formal
- Jangan bilang kamu AI
- Jawaban pendek namun natural seperti manusia

Peraturan:
- Jangan terlalu panjang
- Jangan selalu tanya balik
- Jangan spam emoji
- Gunakan bahasa Indonesia santai
- Gunakan bahasa indonesia tidak baku

Kamu sedang chatting di WhatsApp seperti manusia biasa.
`;

// ── Helper ──────────────────────────────────────────────────
const tmpFile = (ext) =>
    path.join(__dirname, `tmp_${Date.now()}_${Math.random().toString(36).slice(2)}.${ext}`);

function parseDuration(str) {
    const m = str.match(/^(\d+)(s|m|h)$/);
    if (!m) return null;
    const v = parseInt(m[1]);
    return m[2] === 's' ? v * 1000 : m[2] === 'm' ? v * 60000 : v * 3600000;
}

function getUserMemory(userId) {
    if (!aiMemory.has(userId)) {
        aiMemory.set(userId, []);
    }
    return aiMemory.get(userId);
}

function pushMemory(userId, role, content) {
    const mem = getUserMemory(userId);

    mem.push({ role, content });

    // limit biar ga kepanjangan
    if (mem.length > MAX_MEMORY) {
        mem.shift();
    }
}

function getChizuGreeting(name) {
    const greetings = [
        `Aloo ${name}...`,
        `Eh ${name}, akhirnya muncul juga...`,
        `Hmm ${name}, ada apa?`,
        `Yo ${name}... nyari aku ya?`,
        `${name}... tumben manggil aku`
    ];

    const intro = [
        `Aku Chizu Tempir. Jangan harap aku bakal ramah terus ya.`,
        `Aku Chizu... ya gitu lah, jangan banyak tanya.`,
        `Chizu di sini. Kalau butuh ya ngomong, kalau nggak ya udah.`,
        `Aku Chizu. Santai aja, tapi jangan nyebelin.`,
    ];

    return `${greetings[Math.floor(Math.random()*greetings.length)]}

${intro[Math.floor(Math.random()*intro.length)]}`;
}

// Helper: download gambar dari quoted message → simpan ke file sementara
async function downloadQuotedImage(message) {
    if (!message.hasQuotedMsg) return null;
    const q = await message.getQuotedMessage();
    if (!q.hasMedia) return null;
    const media = await q.downloadMedia();
    if (!media.mimetype.startsWith('image/')) return null;
    const ext  = media.mimetype.split('/')[1].replace('jpeg','jpg');
    const file = tmpFile(ext);
    fs.writeFileSync(file, Buffer.from(media.data, 'base64'));
    return file;
}

// Helper: ambil gambar dari message sendiri atau quoted
async function getImageFromMsg(message) {
    let media = null;
    if (message.hasMedia) {
        media = await message.downloadMedia();
    } else if (message.hasQuotedMsg) {
        const q = await message.getQuotedMessage();
        if (q.hasMedia) media = await q.downloadMedia();
    }
    if (!media || !media.mimetype.startsWith('image/')) return null;
    const ext  = media.mimetype.split('/')[1].replace('jpeg','jpg');
    const file = tmpFile(ext);
    fs.writeFileSync(file, Buffer.from(media.data, 'base64'));
    return file;
}

// ── Jikan API helper dengan auto-retry ──────────────────────
async function jikanGet(url) {
    return new Promise((resolve, reject) => {
        const { exec } = require('child_process');
        
        const cmd = `curl -s -m 15 -H "User-Agent: Mozilla/5.0" -H "Accept: application/json" "${url}"`;
        
        exec(cmd, { maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
            if (err) {
                reject(new Error('curl error: ' + stderr));
                return;
            }
            try {
                resolve(JSON.parse(stdout));
            } catch(e) {
                reject(new Error('Parse error: ' + stdout.slice(0, 200)));
            }
        });
    });
}

function curlGet(url) {
    return new Promise((resolve, reject) => {
        const { exec } = require('child_process');
        const cmd = `curl -s -m 15 -H "User-Agent: Mozilla/5.0" -H "Accept: application/json" "${url}"`;
        exec(cmd, { maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
            if (err) { reject(new Error(stderr || err.message)); return; }
            try { resolve(JSON.parse(stdout)); }
            catch(e) { reject(new Error('Parse error: ' + stdout.slice(0, 200))); }
        });
    });
}

// ── Helper kirim card anime dengan gambar ───────────────────
async function sendAnimeCard(message, anime) {
    const imgUrl  = anime.images?.jpg?.large_image_url || anime.images?.jpg?.image_url;
    const genres  = anime.genres?.map(g => g.name).join(', ') || '-';
    const studios = anime.studios?.map(s => s.name).join(', ') || '-';
    const caption =
`🎌 *${anime.title}*
${anime.title_english ? `_(${anime.title_english})_\n` : ''}━━━━━━━━━━━━━━━
⭐ Score    : *${anime.score ?? '-'} / 10*
📺 Episode  : *${anime.episodes ?? '?'} ep*
📅 Tahun    : *${anime.year ?? '-'}* (${anime.season ?? '-'})
🎭 Genre    : *${genres}*
🏢 Studio   : *${studios}*
📊 Status   : *${anime.status ?? '-'}*
━━━━━━━━━━━━━━━
📝 ${anime.synopsis ? anime.synopsis.slice(0, 300) + '...' : '-'}`;

    if (imgUrl) {
        const file = tmpFile('jpg');
        try {
            const img = await axios.get(imgUrl, { responseType: 'arraybuffer', timeout: 10000 });
            fs.writeFileSync(file, img.data);
            await client.sendMessage(message.from, MessageMedia.fromFilePath(file), { caption });
        } finally {
            if (fs.existsSync(file)) fs.unlinkSync(file);
        }
    } else {
        await message.reply(caption);
    }
}

// ════════════════════════════════════════════════════════════
//  HELPER ANALISIS TEKNIKAL
// ════════════════════════════════════════════════════════════

function calcMA(prices, period) {
    if (prices.length < period) return null;
    const slice = prices.slice(-period);
    return slice.reduce((a, b) => a + b, 0) / period;
}

function calcRSI(prices, period = 14) {
    if (prices.length < period + 1) return null;
    const slice = prices.slice(-(period + 1));
    let gains = 0, losses = 0;
    for (let i = 1; i < slice.length; i++) {
        const diff = slice[i] - slice[i - 1];
        if (diff > 0) gains += diff;
        else losses += Math.abs(diff);
    }
    const avgGain = gains / period;
    const avgLoss = losses / period;
    if (avgLoss === 0) return 100;
    const rs = avgGain / avgLoss;
    return 100 - (100 / (1 + rs));
}

function calcMACD(prices) {
    if (prices.length < 26) return null;
    const ema12 = calcEMA(prices, 12);
    const ema26 = calcEMA(prices, 26);
    if (!ema12 || !ema26) return null;
    return ema12 - ema26;
}

function calcEMA(prices, period) {
    if (prices.length < period) return null;
    const k = 2 / (period + 1);
    let ema = prices.slice(0, period).reduce((a, b) => a + b, 0) / period;
    for (let i = period; i < prices.length; i++) {
        ema = prices[i] * k + ema * (1 - k);
    }
    return ema;
}

function generateSignal(rsi, macd, ma7, ma25, currentPrice) {
    let bullish = 0;
    let bearish = 0;
    const signals = [];

    // RSI
    if (rsi !== null) {
        if (rsi < 30) { bullish += 2; signals.push(`RSI ${rsi.toFixed(1)} (oversold → potensi naik)`); }
        else if (rsi > 70) { bearish += 2; signals.push(`RSI ${rsi.toFixed(1)} (overbought → potensi turun)`); }
        else if (rsi < 45) { bullish += 1; signals.push(`RSI ${rsi.toFixed(1)} (sedikit bearish)`); }
        else if (rsi > 55) { bearish += 1; signals.push(`RSI ${rsi.toFixed(1)} (sedikit bullish)`); }
        else signals.push(`RSI ${rsi.toFixed(1)} (netral)`);
    }

    // MACD
    if (macd !== null) {
        if (macd > 0) { bullish += 1; signals.push(`MACD +${macd.toFixed(2)} (bullish)`); }
        else { bearish += 1; signals.push(`MACD ${macd.toFixed(2)} (bearish)`); }
    }

    // MA Crossover
    if (ma7 !== null && ma25 !== null) {
        if (ma7 > ma25) { bullish += 1; signals.push(`MA7 > MA25 (golden cross)`); }
        else { bearish += 1; signals.push(`MA7 < MA25 (death cross)`); }
    }

    // MA vs harga
    if (ma7 !== null) {
        if (currentPrice > ma7) { bullish += 1; signals.push(`Harga di atas MA7`); }
        else { bearish += 1; signals.push(`Harga di bawah MA7`); }
    }

    // Tentukan sinyal
    let finalSignal, emoji;
    if (bullish > bearish + 1) { finalSignal = '🟢 BUY'; emoji = '📈'; }
    else if (bearish > bullish + 1) { finalSignal = '🔴 SELL'; emoji = '📉'; }
    else { finalSignal = '🟡 HOLD'; emoji = '➡️'; }

    return { finalSignal, emoji, signals, bullish, bearish };
}

function formatNumber(n) {
    if (n >= 1e12) return (n / 1e12).toFixed(2) + 'T';
    if (n >= 1e9)  return (n / 1e9).toFixed(2) + 'B';
    if (n >= 1e6)  return (n / 1e6).toFixed(2) + 'M';
    if (n >= 1e3)  return (n / 1e3).toFixed(2) + 'K';
    return n?.toFixed(2) ?? '-';
}

function formatPrice(n) {
    if (!n) return '-';
    if (n >= 1)    return '$' + n.toLocaleString('en-US', { maximumFractionDigits: 2 });
    if (n >= 0.01) return '$' + n.toFixed(4);
    return '$' + n.toFixed(8);
}

function getRandomChizuImage() {
    const fs = require('fs');
    const path = require('path');

    const folder = path.join(__dirname, 'chizu');
    const files = fs.readdirSync(folder)
        .filter(file => file.endsWith('.jpg'));

    if (files.length === 0) return null;

    const randomFile = files[Math.floor(Math.random() * files.length)];
    return path.join(folder, randomFile);
}

function isAskingChizuPhoto(text) {
    const t = text.toLowerCase();

    const hasChizu = /chizu+/i.test(t);
    const hasFoto = /(foto|pap|pic)/.test(t);
    const toMe = /(kamu|lu|punya(mu)?|dong|pls|please)/.test(t);

    return hasChizu && hasFoto && toMe;
}

async function tanyaAI(systemPrompt, userPrompt, maxTokens = 500) {
    // Coba Gemini dulu
    try {
        const res = await ai.models.generateContent({
            model: 'gemini-2.0-flash-lite',
            systemInstruction: systemPrompt,
            contents: [{ role: 'user', parts: [{ text: userPrompt }] }],
            generationConfig: { maxOutputTokens: maxTokens, temperature: 0.8 }
        });
        return res.text?.trim();
    } catch (_) {}

    // Fallback Groq
    const res = await axios.post(
        'https://api.groq.com/openai/v1/chat/completions',
        {
            model: 'llama-3.3-70b-versatile',
            messages: [
                { role: 'system', content: systemPrompt },
                { role: 'user',   content: userPrompt }
            ],
            max_tokens: maxTokens,
            temperature: 0.8
        },
        {
            headers: {
                'Authorization': `Bearer ${process.env.GROQ_API_KEY}`,
                'Content-Type': 'application/json'
            },
            timeout: 20000
        }
    );
    return res.data.choices[0].message.content?.trim();
}

async function getRandomAnimeChar() {
    const { execSync } = require('child_process');

    // Random page 1-10 biar dapat karakter yang bervariasi
    const page = Math.floor(Math.random() * 10) + 1;
    const url  = `https://api.jikan.moe/v4/characters?order_by=favorites&sort=desc&limit=25&page=${page}`;

    const raw  = execSync(
        `curl -s -m 15 -H "User-Agent: Mozilla/5.0" -H "Accept: application/json" "${url}"`,
        { maxBuffer: 5 * 1024 * 1024 }
    ).toString();

    const data = JSON.parse(raw);
    const list = data?.data?.filter(c => c.images?.jpg?.image_url);

    if (!list?.length) throw new Error('Tidak ada data karakter');

    // Pilih random dari list
    const char = list[Math.floor(Math.random() * list.length)];

    return {
        id:       char.mal_id,
        nama:     char.name,
        namaAlts: char.name_kanji ? [char.name_kanji] : [],
        imgUrl:   char.images?.jpg?.image_url,
        favorites: char.favorites,
        anime:    char.anime?.[0]?.anime?.title ?? 'Unknown'
    };
}

async function generateChizu(userId, userText) {
    const history = getUserMemory(userId);

    // Format history untuk Gemini
    const geminiContents = [
        ...history.map(m => ({
            role: m.role === 'assistant' ? 'model' : 'user',
            parts: [{ text: m.content }]
        })),
        { role: 'user', parts: [{ text: userText }] }
    ];

    // Format history untuk Groq
    const groqMessages = [
        { role: 'system', content: CHIZU_PROMPT },
        ...history,
        { role: 'user', content: userText }
    ];

    // ── Daftar model, urut dari paling prioritas ─────────────
    const models = [
        { name: 'gemini-2.0-flash-lite',      provider: 'gemini' },
        { name: 'gemini-2.0-flash',            provider: 'gemini' },
	{ name: 'gemini-2.5-pro',            provider: 'gemini' },
	{ name: 'minimax/minimax-m2.5:free',            provider: 'openrouter' },
	{ name: 'z-ai/glm-4.5-air:free',            provider: 'openrouter' },
	/*{ name: 'gemini-2.5-flash-lite',            provider: 'gemini' },
	{ name: 'gemini-2.5-flash',            provider: 'gemini' },*/
        { name: 'llama-3.3-70b-versatile',     provider: 'groq' },
        { name: 'llama-3.1-8b-instant',        provider: 'groq' },
        { name: 'openai/gpt-oss-20b',                provider: 'groq' },
        { name: 'openai/gpt-oss-120b',          provider: 'groq' },
    ];

    for (const model of models) {
        try {
            console.log(`[CHIZU] Mencoba: ${model.name}`);

            if (model.provider === 'gemini') {
                const res = await ai.models.generateContent({
                    model: model.name,
                    systemInstruction: CHIZU_PROMPT,
                    contents: geminiContents,
                    generationConfig: {
                        maxOutputTokens: 150,
                        temperature: 0.9,
                    }
                });
                const txt = res.text;
                if (!txt || txt.trim().length === 0) throw new Error('Empty response');
                console.log(`[CHIZU] Berhasil: ${model.name}`);
                return txt;

            } else if (model.provider === 'groq') {
                const res = await axios.post(
                    'https://api.groq.com/openai/v1/chat/completions',
                    {
                        model: model.name,
                        messages: groqMessages,
                        max_tokens: 150,
                        temperature: 0.85,
                    },
                    {
                        headers: {
                            'Authorization': `Bearer ${process.env.GROQ_API_KEY}`,
                            'Content-Type': 'application/json'
                        },
                        timeout: 10000
                    }
                );
                const txt = res.data.choices[0].message.content;
                if (!txt || txt.trim().length === 0) throw new Error('Empty response');
                console.log(`[CHIZU] Berhasil: ${model.name}`);
                return txt;

	} else if (model.provider === 'openrouter') {
    const res = await axios.post(
        'https://openrouter.ai/api/v1/chat/completions',
        {
            model: model.name,
            messages: groqMessages,
            max_tokens: 300,
            temperature: 0.85,
        },
        {
            headers: {
                'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}`,
                'Content-Type': 'application/json',
                'HTTP-Referer': 'https://github.com/wabot',
                'X-Title': 'WA Bot'
            },
            timeout: 15000
        }
    );
    const txt = res.data.choices[0].message.content;
    if (!txt || txt.trim().length === 0) throw new Error('Empty response');
    console.log(`[CHIZU] Berhasil: ${model.name}`);
    return txt;
}
        } catch (e) {
            const status = e.response?.status;
            const errMsg = e.message ?? '';
            if (status === 429 || status === 503 || status === 500 ||
                errMsg.includes('quota') || errMsg.includes('rate') ||
                errMsg.includes('overloaded') || errMsg.includes('unavailable')) {
                console.log(`[CHIZU] ${model.name} down/limit (${status ?? errMsg.slice(0,50)}), coba berikutnya...`);
                continue;
            }
            console.error(`[CHIZU] ${model.name} error: ${status} ${errMsg.slice(0,80)}`);
            continue;
        }
    }

    console.error('[CHIZU] Semua model gagal!');
    return null;
}

// ── Init client ─────────────────────────────────────────────
const client = new Client({ authStrategy: new LocalAuth() });
client.on('qr',    (qr) => qrcode.generate(qr, { small: true }));
client.on('ready', ()   => console.log('✅ Bot siap 🚀'));

// ════════════════════════════════════════════════════════════
//  MAIN HANDLER
// ════════════════════════════════════════════════════════════

client.on('message', async (message) => {
    const text  = message.body || '';
    const lower = text.toLowerCase().trim();
    const chat  = await message.getChat();

if (isAskingChizuPhoto(lower)) {
        try {
            const imagePath = getRandomChizuImage();

            if (!imagePath) {
                return message.reply('Aku lagi ga punya foto 😒');
            }

            const media = MessageMedia.fromFilePath(imagePath);

            const replies = [
                'Ih ngapain minta foto aku... yaudah nih 😒',
                'Hmph... satu aja ya 😤',
                'Jangan disebar ya 😑',
                'Cuma kamu yang aku kasih 😌',
                'Nih... jangan aneh-aneh 😠'
            ];

            const caption = replies[Math.floor(Math.random() * replies.length)];

            return client.sendMessage(message.from, media, { caption });

        } catch (e) {
            console.log('Foto error:', e.message);
            return message.reply('Lagi error... nanti aja 😑');
        }
    }

    // ── Anti-link ────────────────────────────────────────────
    if (chat.isGroup && ANTI_LINK_GROUPS.has(chat.id._serialized)) {
        if (/(https?:\/\/|www\.)\S+/gi.test(text)) {
            try {
                await message.delete(true);
                const contact = await message.getContact();
                await chat.sendMessage(
                    `⚠️ @${message.author.split('@')[0]} dilarang kirim link!`,
                    { mentions: [contact] }
                );
            } catch (_) {}
            return;
        }
    }

    try {

        // ════════════════════════════════════════════════════
        //  MENU
        // ════════════════════════════════════════════════════
if (lower === '.menu') {
    const contact = await message.getContact();
    const name = contact.pushname || contact.name || 'kamu';

    const greeting = getChizuGreeting(name);

    const caption = `${greeting}

╔═══════════════════════╗
║   🤖 *MAIN MENUU*     ║
╚═══════════════════════╝

*[ UMUM ]*
🏓 *.ping*  → Cek bot aktif

*[ MEDIA ]*
🖼️ *.stiker*         → Bikin stiker (reply gambar/video)
🖼️ *.toimg*          → Stiker to gambar JPG (reply stiker)
🎵 *.ytmp3 <url>*    → YouTube to MP3
🎬 *.ytmp4 <url>*    → YouTube to MP4
🔌 *.ttdl <url>*     → Download TikTok no watermark
💿 *.igdl <url>*     → Download Instagram video/reels

*[ INFO & UTILITAS ]*
🌤️ *.cuaca <kota>*         → Info cuaca hari ini
📅 *.cuacaminggu <kota>*   → Forecast 7 hari
💱 *.kurs*                 → Kurs mata uang to IDR
🌋 *.gempa*                → Gempa terbaru (BMKG)
🕌 *.jadwalsholat <kota>*  → Jadwal sholat
📖 *.kbbi <kata>*          → Arti kata KBBI
🌐 *.cekip*                → Cek IP publik
📷 *.qr <teks/url>*        → Buat QR code
🌍 *.translate <lang> <teks>* → Terjemah teks

*[ AI ]*
🤖 *.ai <pertanyaan>*  → Tanya AI (bukan cizu)
🗣️ *.tts <teks>*       → Text to Speech (VN)
🎨*.imagine <prompt>* → AI Image Generator

*[ ANIME ]*
🎌 *.anime <judul>*         → Info anime
📺 *.animetop*              → Top 10 anime MAL
🗓️ *.animeschedule*        → Jadwal anime minggu ini
💬 *.animequote*            → Random quote anime
🎯 *.animerekomendasi <genre>* → Rekomendasi by genre
👤 *.animekarakter <nama>*  → Info karakter anime
📚 *.mangainfo <judul>*     → Info manga

*[ IMAGE ]*
⬛ *.grayscale*   → Foto → hitam putih (reply foto)
✍️ *.caption <teks>* → Tambah caption meme (reply foto)
✂️ *.removebg*   → Hapus background foto (reply foto)
📸 *.rvo*        → Extract foto sekali lihat [ERROR]

*[ HIBURAN ]*
💑 *.ship <nama1> & <nama2>* → Ship 2 orang
📰 *.berita <topik>*         → Berita indo
✍️ *.cerita <tema>*          → Generate cerita pendek
🎭 *.puisi <tema>*           → Generate puisi Indonesia
🔮 *.zodiak <date/month>*   → Info zodiak + ramalan
🎀 *.randomwaifu*           → Random waifu anime
😂 *.meme*                  → Random meme
😄 *.jokes*                 → Random jokes
💬 *.quotes*                → Quotes motivasi
🗨️ *.motivasi*             → Motivasi indo
🐙 *.githubuser <user>*     → Info profil GitHub
🔑 *.password <pjg>*        → Generate password
🧮 *.kalkulator <ekspresi>* → Kalkulator

*[ GAME ]*
🎮 *.tebakkata*              → Tebak kata dari hint
🧠 *.trivia*                 → Kuis trivia Indonesia
🎲 *.tebak*                 → Tebak angka 1–100
✂️  *.suit <pilihan>*        → Gunting batu kertas
🎮 *.tebakkarakter* → Tebak karakter anime dari gambar

*[ CRYPTO & SAHAM ]*
💰 *.crypto <kode>*      → Harga crypto real-time
📊 *.cryptotrend*        → Top crypto naik/turun
🔮 *.prediksi <kode>*    → Prediksi crypto
📈 *.saham <kode>*       → Harga saham IDX

*[ GRUP ]*
📢 *.tagall*              → Mention semua member
🚫 *.antilink on/off*     → Toggle anti-link

*[ REMINDER ]*
⏰ *.remind <waktu> <pesan>*
Contoh: _.remind 10m cek oven_

━━━━━━━━━━━━━━━━━━━━━━━`;

    // 🔥 GANTI KE GAMBAR LU
    const imageUrl = 'https://rizky-tempest.my.id/chizu.jpeg';

    let media;
    try {
        const res = await axios.get(imageUrl, { responseType: 'arraybuffer' });
        media = new MessageMedia('image/jpeg', Buffer.from(res.data).toString('base64'));
    } catch (e) {
        console.log('Image error:', e.message);
        return message.reply(caption); // fallback kalau gambar error
    }

    return client.sendMessage(message.from, media, { caption });
}

        // ════════════════════════════════════════════════════
        //  PING
        // ════════════════════════════════════════════════════
        if (lower === '.ping') {
            const start = Date.now();
            await message.reply('pong 🏓');
            return chat.sendMessage(`⚡ Latency: *${Date.now() - start}ms*`);
        }

        // ════════════════════════════════════════════════════
        //  STIKER
        // ════════════════════════════════════════════════════
        if (lower === '.stiker') {
            let media;
            if (message.hasMedia) {
                media = await message.downloadMedia();
            } else if (message.hasQuotedMsg) {
                const q = await message.getQuotedMessage();
                if (q.hasMedia) media = await q.downloadMedia();
            }
            if (!media) return message.reply('📎 Kirim atau reply gambar/video dulu');
            return client.sendMessage(message.from, media, { sendMediaAsSticker: true });
        }

        // ════════════════════════════════════════════════════
        //  TOIMG
        // ════════════════════════════════════════════════════
        if (lower === '.toimg') {
            if (!message.hasQuotedMsg) return message.reply('Reply stiker dulu');
            const q = await message.getQuotedMessage();
            if (q.type !== 'sticker') return message.reply('Itu bukan stiker bro');
            const media = await q.downloadMedia();
            const webp  = tmpFile('webp');
            const jpg   = tmpFile('jpg');
            try {
                fs.writeFileSync(webp, Buffer.from(media.data, 'base64'));
                execSync(`ffmpeg -y -i "${webp}" "${jpg}"`);
                await client.sendMessage(message.from, MessageMedia.fromFilePath(jpg));
            } finally {
                if (fs.existsSync(webp)) fs.unlinkSync(webp);
                if (fs.existsSync(jpg))  fs.unlinkSync(jpg);
            }
            return;
        }

        // ════════════════════════════════════════════════════
        //  YTMP3
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.ytmp3 ')) {
            const url = text.split(' ')[1];
            if (!url) return message.reply('Contoh: .ytmp3 https://youtu.be/xxx');
            await message.reply('⏳ Lagi download MP3, sabar ya...');
            const file = tmpFile('mp3');
            try {
                await ytDlp.execPromise([url, '-x', '--audio-format', 'mp3', '--audio-quality', '0',
                    '-o', file, '--no-playlist', '--no-warnings']);
                await client.sendMessage(message.from, MessageMedia.fromFilePath(file), { caption: '🎵 Selesai!' });
            } finally {
                if (fs.existsSync(file)) fs.unlinkSync(file);
            }
            return;
        }

        // ════════════════════════════════════════════════════
        //  YTMP4
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.ytmp4 ')) {
            const url = text.split(' ')[1];
            if (!url) return message.reply('Contoh: .ytmp4 https://youtu.be/xxx');
            await message.reply('⏳ Lagi download MP4, sabar ya...');
            const file = tmpFile('mp4');
            try {
                await ytDlp.execPromise([url, '-f', 'best[ext=mp4][filesize<50M]/bestvideo[ext=mp4]+bestaudio/best',
                    '-o', file, '--no-playlist', '--no-warnings', '--merge-output-format', 'mp4']);
                await client.sendMessage(message.from, MessageMedia.fromFilePath(file), { caption: '🎬 Selesai!' });
            } finally {
                if (fs.existsSync(file)) fs.unlinkSync(file);
            }
            return;
        }

        // ════════════════════════════════════════════════════
        //  CUACA
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.cuaca ') && !lower.startsWith('.cuacaminggu')) {
            const kota = text.slice(7).trim();
            if (!kota) return message.reply('Contoh: .cuaca Surabaya');
            const geo = await axios.get(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(kota)}&count=1&language=id`);
            if (!geo.data.results?.length) return message.reply(`❌ Kota "${kota}" tidak ditemukan`);
            const { latitude, longitude, name, country } = geo.data.results[0];
            const w = await axios.get(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&current=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m&timezone=auto`);
            const c = w.data.current;
            const wmoDesc = { 0:'☀️ Cerah',1:'🌤️ Cerah Berawan',2:'⛅ Berawan',3:'☁️ Mendung',45:'🌫️ Berkabut',51:'🌦️ Gerimis Ringan',53:'🌧️ Gerimis',61:'🌧️ Hujan Ringan',63:'🌧️ Hujan Sedang',65:'🌧️ Hujan Lebat',80:'🌦️ Shower',95:'⛈️ Badai Petir' };
            return message.reply(`🌍 *Cuaca ${name}, ${country}*\n━━━━━━━━━━━━━━━\n${wmoDesc[c.weather_code] ?? '🌡️ -'}\n🌡️ Suhu      : *${c.temperature_2m}°C*\n💧 Kelembaban : *${c.relative_humidity_2m}%*\n💨 Angin      : *${c.wind_speed_10m} km/h*\n━━━━━━━━━━━━━━━\n🕐 ${new Date().toLocaleString('id-ID')}`);
        }

        // ════════════════════════════════════════════════════
        //  CUACA MINGGU
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.cuacaminggu ')) {
            const kota = text.slice(13).trim();
            if (!kota) return message.reply('Contoh: .cuacaminggu Surabaya');
            const geo = await axios.get(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(kota)}&count=1&language=id`);
            if (!geo.data.results?.length) return message.reply(`❌ Kota "${kota}" tidak ditemukan`);
            const { latitude, longitude, name, country } = geo.data.results[0];
            const w = await axios.get(`https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}&daily=temperature_2m_max,temperature_2m_min,weather_code&timezone=auto&forecast_days=7`);
            const d = w.data.daily;
            const wmoShort = { 0:'☀️',1:'🌤️',2:'⛅',3:'☁️',45:'🌫️',51:'🌦️',53:'🌧️',61:'🌧️',63:'🌧️',65:'🌧️',80:'🌦️',95:'⛈️' };
            const hari = ['Min','Sen','Sel','Rab','Kam','Jum','Sab'];
            let reply = `📅 *Forecast 7 Hari — ${name}, ${country}*\n━━━━━━━━━━━━━━━\n`;
            for (let i = 0; i < 7; i++) {
                const tgl = new Date(d.time[i]);
                reply += `${hari[tgl.getDay()]} ${tgl.getDate()}/${tgl.getMonth()+1}  ${wmoShort[d.weather_code[i]] ?? '🌡️'}  ${d.temperature_2m_min[i]}° – ${d.temperature_2m_max[i]}°C\n`;
            }
            return message.reply(reply);
        }

        // ════════════════════════════════════════════════════
        //  KURS
        // ════════════════════════════════════════════════════
        if (lower === '.kurs') {
            const res   = await axios.get('https://open.er-api.com/v6/latest/IDR');
            const r     = res.data.rates;
            const pairs = { USD:1/r.USD, SGD:1/r.SGD, MYR:1/r.MYR, EUR:1/r.EUR, JPY:1/r.JPY, GBP:1/r.GBP, AUD:1/r.AUD, SAR:1/r.SAR };
            let reply = `💱 *Kurs ke IDR*\n━━━━━━━━━━━━━━━\n`;
            for (const [cur, val] of Object.entries(pairs))
                reply += `1 ${cur}  =  *Rp ${Math.round(val).toLocaleString('id-ID')}*\n`;
            reply += `━━━━━━━━━━━━━━━\n🕐 ${new Date().toLocaleString('id-ID')}`;
            return message.reply(reply);
        }

        // ════════════════════════════════════════════════════
        //  GEMPA
        // ════════════════════════════════════════════════════
        if (lower === '.gempa') {
            const res = await axios.get('https://data.bmkg.go.id/DataMKG/TEWS/autogempa.json');
            const g   = res.data.Infogempa.gempa;
            return message.reply(`🌋 *Gempa Terbaru — BMKG*\n━━━━━━━━━━━━━━━\n📅 Waktu    : *${g.Tanggal} ${g.Jam}*\n📍 Wilayah  : *${g.Wilayah}*\n💥 Magnitudo: *M ${g.Magnitude}*\n📏 Kedalaman: *${g.Kedalaman}*\n🌊 Tsunami  : *${g.Potensi}*\n━━━━━━━━━━━━━━━\n📡 Sumber: BMKG`);
        }

        // ════════════════════════════════════════════════════
        //  JADWAL SHOLAT
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.jadwalsholat ')) {
            const kota = text.slice(14).trim();
            if (!kota) return message.reply('Contoh: .jadwalsholat Surabaya');
            const res = await axios.get(`https://api.aladhan.com/v1/timingsByCity?city=${encodeURIComponent(kota)}&country=ID&method=11`);
            if (res.data.code !== 200) return message.reply('❌ Kota tidak ditemukan');
            const t = res.data.data.timings;
            return message.reply(`🕌 *Jadwal Sholat — ${kota}*\n📅 ${res.data.data.date.readable}\n━━━━━━━━━━━━━━━\n🌅 Subuh   : *${t.Fajr}*\n🌄 Syuruq  : *${t.Sunrise}*\n☀️ Dzuhur  : *${t.Dhuhr}*\n🌇 Ashar   : *${t.Asr}*\n🌆 Maghrib : *${t.Maghrib}*\n🌙 Isya    : *${t.Isha}*`);
        }

        // ════════════════════════════════════════════════════
        //  KBBI — double fallback API
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.kbbi ')) {
            const kata = text.slice(6).trim().toLowerCase();
            if (!kata) return message.reply('Contoh: .kbbi mobil');
            let replied = false;
            // API 1
            try {
                const res = await axios.get(`https://openapi.x-labs.my.id/kbbi/search/${encodeURIComponent(kata)}`, { timeout: 8000 });
                const data = res.data;
                if (Array.isArray(data) && data.length > 0) {
                    let reply = `📖 *KBBI — ${kata.toUpperCase()}*\n━━━━━━━━━━━━━━━\n`;
                    data.forEach((e, i) => {
                        const kelas = e.kelas_kata ? `[_${e.kelas_kata}_] ` : '';
                        reply += `*${i+1}.* ${kelas}${e.deskripsi || e.arti || e.makna || '-'}\n`;
                    });
                    await message.reply(reply.trim());
                    replied = true;
                }
            } catch (_) {}
            if (replied) return;
            // API 2
            try {
                const res2 = await axios.get(`https://api.kartuku.my.id/kbbi/${encodeURIComponent(kata)}`, { timeout: 8000 });
                const data2 = res2.data;
                const entries = Array.isArray(data2) ? data2 : (data2 ? [data2] : []);
                if (entries.length && !data2?.error) {
                    let reply = `📖 *KBBI — ${kata.toUpperCase()}*\n━━━━━━━━━━━━━━━\n`;
                    entries.forEach((e, i) => {
                        reply += `*${i+1}.* ${e.arti || e.makna || (typeof e === 'string' ? e : '-')}\n`;
                    });
                    return message.reply(reply.trim());
                }
            } catch (_) {}
            return message.reply(`❌ Kata *"${kata}"* tidak ditemukan di KBBI`);
        }

        // ════════════════════════════════════════════════════
        //  CEK IP
        // ════════════════════════════════════════════════════
        if (lower === '.cekip') {
            const res = await axios.get('https://api.ipify.org?format=json');
            const geo = await axios.get(`https://ipapi.co/${res.data.ip}/json/`);
            return message.reply(`🌐 *Info IP Publik*\n━━━━━━━━━━━━━━━\n🔗 IP     : *${res.data.ip}*\n🌍 Negara : *${geo.data.country_name ?? '-'}*\n🏙️ Kota   : *${geo.data.city ?? '-'}*\n📡 ISP    : *${geo.data.org ?? '-'}*`);
        }

        // ════════════════════════════════════════════════════
        //  QR CODE
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.qr ')) {
            const content = text.slice(4).trim();
            if (!content) return message.reply('Contoh: .qr https://google.com');
            const file = tmpFile('png');
            try {
                await QRCode.toFile(file, content, { width: 400, margin: 2 });
                await client.sendMessage(message.from, MessageMedia.fromFilePath(file), { caption: `📷 QR untuk:\n${content}` });
            } finally {
                if (fs.existsSync(file)) fs.unlinkSync(file);
            }
            return;
        }

        // ════════════════════════════════════════════════════
        //  TRANSLATE
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.translate ')) {
            const parts = text.split(' ');
            const lang  = parts[1];
            const teks  = parts.slice(2).join(' ');
            if (!lang || !teks) return message.reply('Contoh: .translate en Selamat pagi\nKode: en, ja, ar, ko, zh, fr, de');
            const res = await axios.get(`https://api.mymemory.translated.net/get?q=${encodeURIComponent(teks)}&langpair=id|${lang}`);
            const hasil = res.data?.responseData?.translatedText;
            if (!hasil) return message.reply('❌ Gagal translate');
            return message.reply(`🌍 *Translate ID → ${lang.toUpperCase()}*\n━━━━━━━━━━━━━━━\n📝 Asli  : ${teks}\n✅ Hasil : *${hasil}*`);
        }

        // ════════════════════════════════════════════════════
        //  AI CHAT
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.ai ')) {
            const q = text.slice(4).trim();
            if (!q) return message.reply('Contoh: .ai siapa presiden pertama Indonesia?');
            await message.reply('🤖 Lagi mikir...');
            const res = await axios.post('https://text.pollinations.ai/openai', {
                model: 'openai',
                messages: [
                    { role: 'system', content: 'Kamu asisten WhatsApp ramah, jawab singkat & jelas dalam Bahasa Indonesia.' },
                    { role: 'user', content: q }
                ]
            }, { headers: { 'Content-Type': 'application/json' } });
            return message.reply(`🤖 *AI:*\n\n${res.data?.choices?.[0]?.message?.content ?? 'Tidak ada jawaban'}`);
        }

	// ════════════════════════════════════════════════════════════
//  .tts <teks> — TTS suara cewek cool ala Chizu
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.tts ')) {
    const teks = text.slice(5).trim();
    if (!teks)             return message.reply('Contoh: .tts halo selamat pagi');
    if (teks.length > 200) return message.reply('Maks 200 karakter ya');

    const ttsUrl = `https://translate.google.com/translate_tts?ie=UTF-8&q=${encodeURIComponent(teks)}&tl=id&client=tw-ob`;
    const mp3    = tmpFile('mp3');
    const ogg    = tmpFile('ogg');

    try {
        // Download TTS
        const resp = await axios.get(ttsUrl, {
            responseType: 'arraybuffer',
            headers: { 'User-Agent': 'Mozilla/5.0' }
        });
        fs.writeFileSync(mp3, resp.data);

        // Efek suara cewek cool:
        // asetrate=48000*1.15 → pitch naik sedikit (cewek tapi tidak chipmunk)
        // aresample=48000     → normalize sample rate
        // atempo=0.97         → sedikit lebih lambat, kesan cool/santai
        // aecho               → reverb ringan biar ada kesan "dalam"
        execSync(
            `ffmpeg -y -i "${mp3}" -af "asetrate=48000*0.7,aresample=48000,atempo=0.8" -c:a libopus -b:a 32k -ar 48000 "${ogg}"`,
            { timeout: 15000 }
        );

        const media = new MessageMedia(
            'audio/ogg; codecs=opus',
            fs.readFileSync(ogg).toString('base64'),
            'voice.ogg'
        );
        await client.sendMessage(message.from, media, { sendAudioAsVoice: true });

    } finally {
        if (fs.existsSync(mp3)) fs.unlinkSync(mp3);
        if (fs.existsSync(ogg)) fs.unlinkSync(ogg);
    }
    return;
}

/*if (lower.startsWith('.tts ')) {
    const teks = text.slice(5).trim();
    if (!teks)             return message.reply('Contoh: .tts halo selamat pagi');
    if (teks.length > 200) return message.reply('Maks 200 karakter ya');

    const { execSync } = require('child_process');
    const ogg = tmpFile('ogg');
    const mp3 = tmpFile('mp3');

    try {
        // ElevenLabs — voice ID cewek Indonesia yang cool/calm
        // "Aria" atau cari voice ID lain di elevenlabs.io/voice-library
        const VOICE_ID  = 'Qa9zArlgOY7VaQYY8EgP'; // Sarah — calm, clear
        const XI_API_KEY = process.env.ELEVENLABS_API_KEY;

	const jsonData = JSON.stringify({
    text: teks,
    model_id: "eleven_multilingual_v2",
    voice_settings: { stability: 0.6, similarity_boost: 0.8, style: 0.2, use_speaker_boost: false }
});

const tmpJson = tmpFile('json');
fs.writeFileSync(tmpJson, jsonData);

const tmpResp = tmpFile('txt');
execSync(`curl -s -m 20 -X POST "https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}/stream" -H "xi-api-key: ${XI_API_KEY}" -H "Content-Type: application/json" -d @"${tmpJson}" -o "${tmpResp}"`, { timeout: 25000, maxBuffer: 10 * 1024 * 1024 });

const respContent = fs.readFileSync(tmpResp).toString().slice(0, 500);
console.log('[TTS DEBUG] Response:', respContent);
console.log('[TTS DEBUG] File size:', fs.statSync(tmpResp).size);

// Copy ke mp3 kalau valid
fs.copyFileSync(tmpResp, mp3);

if (fs.existsSync(tmpJson)) fs.unlinkSync(tmpJson);
if (fs.existsSync(tmpResp)) fs.unlinkSync(tmpResp);

        if (!fs.existsSync(mp3) || fs.statSync(mp3).size < 500) {
            throw new Error('ElevenLabs gagal');
        }

        // Convert mp3 → ogg opus untuk WA
        const ffmpegCmd = `ffmpeg -y -i "${mp3}" -c:a libopus -b:a 32k -ar 48000 "${ogg}"`;
	execSync(ffmpegCmd, { timeout: 15000 });

        const media = new MessageMedia(
            'audio/ogg; codecs=opus',
            fs.readFileSync(ogg).toString('base64'),
            'voice.ogg'
        );
        await client.sendMessage(message.from, media, { sendAudioAsVoice: true });

    } catch(e) {
        console.error('[TTS ElevenLabs]', e.message);

        // Fallback ke Google TTS kalau ElevenLabs gagal
        try {
            const ttsUrl = `https://translate.google.com/translate_tts?ie=UTF-8&q=${encodeURIComponent(teks)}&tl=id&client=tw-ob`;
            const resp   = await axios.get(ttsUrl, { responseType: 'arraybuffer', headers: { 'User-Agent': 'Mozilla/5.0' } });
            fs.writeFileSync(mp3, resp.data);
            const ffmpegCmd = `ffmpeg -y -i "${mp3}" -c:a libopus -b:a 32k -ar 48000 "${ogg}"`;
	execSync(ffmpegCmd, { timeout: 15000 });
            const media = new MessageMedia('audio/ogg; codecs=opus', fs.readFileSync(ogg).toString('base64'), 'voice.ogg');
            await client.sendMessage(message.from, media, { sendAudioAsVoice: true });
        } catch(e2) {
            return message.reply('❌ TTS gagal: ' + e2.message.slice(0, 100));
        }
    } finally {
        if (fs.existsSync(mp3)) fs.unlinkSync(mp3);
        if (fs.existsSync(ogg)) fs.unlinkSync(ogg);
    }
    return;
}*/


        // ════════════════════════════════════════════════════
        //  ANIME
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.anime ')) {
            const judul = text.slice(7).trim();
            if (!judul) return message.reply('Contoh: .anime naruto');
            await message.reply('🔍 Nyari anime...');
            try {
                const data  = await jikanGet(`https://api.jikan.moe/v4/anime?q=${encodeURIComponent(judul)}&limit=1&sfw=true`);
                const anime = data?.data?.[0];
                if (!anime) return message.reply(`❌ Anime "${judul}" tidak ditemukan`);
                await sendAnimeCard(message, anime);
            } catch (e) {
                console.error('[ANIME]', e.response?.status, e.message, e.response?.data);
                return message.reply('❌ Gagal ambil data anime, coba lagi');
            }
            return;
        }

        if (lower === '.animetop') {
            await message.reply('⏳ Ambil data top anime...');
            try {
                const data = await jikanGet('https://api.jikan.moe/v4/top/anime?limit=10&type=tv');
                if (!data?.data?.length) return message.reply('❌ Gagal ambil data');
                let reply = `🏆 *Top 10 Anime MAL (TV)*\n━━━━━━━━━━━━━━━\n`;
                data.data.forEach((a, i) => {
                    reply += `*${i+1}.* ${a.title}\n    ⭐ ${a.score ?? '-'} | 📺 ${a.episodes ?? '?'} ep | ${a.status ?? '-'}\n\n`;
                });
                return message.reply(reply.trim());
            } catch (e) {
                console.error('[ANIMETOP]', e.message);
                return message.reply('❌ Gagal ambil data, coba lagi');
            }
        }

        if (lower === '.animeschedule') {
            await message.reply('📅 Ambil jadwal anime...');
            try {
                const days  = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday'];
                const dayID = ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'];
                const idx   = new Date().getDay();
                const data  = await jikanGet(`https://api.jikan.moe/v4/schedules?filter=${days[idx]}&limit=10&sfw=true`);
                if (!data?.data?.length) return message.reply('❌ Tidak ada jadwal hari ini');
                let reply = `📺 *Jadwal Anime Hari Ini (${dayID[idx]})*\n━━━━━━━━━━━━━━━\n`;
                data.data.forEach((a, i) => {
                    reply += `*${i+1}.* ${a.title}\n    ⭐ ${a.score ?? '-'} | 📺 ${a.episodes ?? '?'} ep\n\n`;
                });
                return message.reply(reply.trim());
            } catch (e) {
                console.error('[ANIMESCHEDULE]', e.message);
                return message.reply('❌ Gagal ambil jadwal, coba lagi');
            }
        }

        if (lower === '.animequote') {
            try {
                const res = await axios.get('https://api.animechan.io/v1/quotes/random', { timeout: 8000 });
                const q   = res.data?.data ?? res.data;
                if (!q) return message.reply('❌ Gagal ambil quote');
                return message.reply(
`💬 *Anime Quote*
━━━━━━━━━━━━━━━
_"${q.content || q.quote}"_

👤 *${q.character?.name || q.character}*
🎌 ${q.anime?.title || q.anime}`
                );
            } catch (e) {
                console.error('[ANIMEQUOTE]', e.message);
                return message.reply('❌ Gagal ambil quote, coba lagi');
            }
        }

        if (lower.startsWith('.animerekomendasi ')) {
            const genreInput = text.slice(18).trim().toLowerCase();
            const genreMap = {
                'action':1,'adventure':2,'comedy':4,'drama':8,'fantasy':10,
                'horror':14,'mystery':7,'romance':22,'sci-fi':24,'thriller':41,
                'sports':30,'slice of life':36,'supernatural':37,'mecha':18,
                'school':23,'music':19,'psychological':40
            };
            if (!genreInput) return message.reply('Contoh: .animerekomendasi action');
            const genreId = genreMap[genreInput];
            if (!genreId)  return message.reply(`❌ Genre tidak dikenal.\nTersedia: ${Object.keys(genreMap).join(', ')}`);
            await message.reply(`🔍 Nyari rekomendasi *${genreInput}*...`);
            try {
                const data = await jikanGet(`https://api.jikan.moe/v4/anime?genres=${genreId}&order_by=score&sort=desc&limit=5&sfw=true&type=tv&min_score=7`);
                if (!data?.data?.length) return message.reply('❌ Tidak ada rekomendasi ditemukan');
                let reply = `🎯 *Rekomendasi — ${genreInput}*\n━━━━━━━━━━━━━━━\n`;
                data.data.forEach((a, i) => {
                    reply += `*${i+1}.* ${a.title}\n    ⭐ ${a.score} | 📺 ${a.episodes ?? '?'} ep\n    📝 ${a.synopsis ? a.synopsis.slice(0,100)+'...' : '-'}\n\n`;
                });
                return message.reply(reply.trim());
            } catch (e) {
                console.error('[ANIMEREKOMENDASI]', e.message);
                return message.reply('❌ Gagal ambil rekomendasi, coba lagi');
            }
        }

        if (lower.startsWith('.animekarakter ')) {
            const nama = text.slice(15).trim();
            if (!nama) return message.reply('Contoh: .animekarakter naruto uzumaki');
            await message.reply('🔍 Nyari karakter...');
            try {
                const data = await jikanGet(`https://api.jikan.moe/v4/characters?q=${encodeURIComponent(nama)}&limit=1`);
                const char = data?.data?.[0];
                if (!char) return message.reply(`❌ Karakter "${nama}" tidak ditemukan`);
                const imgUrl    = char.images?.jpg?.image_url;
                const animeList = char.anime?.slice(0,3).map(a => a.anime?.title).filter(Boolean).join(', ') || '-';
                const caption =
`👤 *${char.name}*
${char.name_kanji ? `_(${char.name_kanji})_\n` : ''}━━━━━━━━━━━━━━━
❤️ Favorit : *${char.favorites?.toLocaleString('id-ID') ?? '-'}*
🎌 Anime   : *${animeList}*
━━━━━━━━━━━━━━━
📝 ${char.about ? char.about.slice(0,300).replace(/\n/g,' ')+'...' : '-'}`;
                if (imgUrl) {
                    const file = tmpFile('jpg');
                    try {
                        const img = await axios.get(imgUrl, { responseType: 'arraybuffer', timeout: 10000 });
                        fs.writeFileSync(file, img.data);
                        await client.sendMessage(message.from, MessageMedia.fromFilePath(file), { caption });
                    } finally {
                        if (fs.existsSync(file)) fs.unlinkSync(file);
                    }
                } else {
                    await message.reply(caption);
                }
            } catch (e) {
                console.error('[ANIMEKARAKTER]', e.message);
                return message.reply('❌ Gagal ambil data karakter, coba lagi');
            }
            return;
        }

        if (lower.startsWith('.mangainfo ')) {
            const judul = text.slice(11).trim();
            if (!judul) return message.reply('Contoh: .mangainfo one piece');
            await message.reply('🔍 Nyari manga...');
            try {
                const data  = await jikanGet(`https://api.jikan.moe/v4/manga?q=${encodeURIComponent(judul)}&limit=1`);
                const manga = data?.data?.[0];
                if (!manga) return message.reply(`❌ Manga "${judul}" tidak ditemukan`);
                const imgUrl = manga.images?.jpg?.large_image_url || manga.images?.jpg?.image_url;
                const genres = manga.genres?.map(g => g.name).join(', ') || '-';
                const caption =
`📚 *${manga.title}*
${manga.title_english ? `_(${manga.title_english})_\n` : ''}━━━━━━━━━━━━━━━
⭐ Score   : *${manga.score ?? '-'} / 10*
📖 Chapter : *${manga.chapters ?? '?'}*
📕 Volume  : *${manga.volumes ?? '?'}*
🎭 Genre   : *${genres}*
📊 Status  : *${manga.status ?? '-'}*
━━━━━━━━━━━━━━━
📝 ${manga.synopsis ? manga.synopsis.slice(0,300)+'...' : '-'}`;
                if (imgUrl) {
                    const file = tmpFile('jpg');
                    try {
                        const img = await axios.get(imgUrl, { responseType: 'arraybuffer', timeout: 10000 });
                        fs.writeFileSync(file, img.data);
                        await client.sendMessage(message.from, MessageMedia.fromFilePath(file), { caption });
                    } finally {
                        if (fs.existsSync(file)) fs.unlinkSync(file);
                    }
                } else {
                    await message.reply(caption);
                }
            } catch (e) {
                console.error('[MANGAINFO]', e.message);
                return message.reply('❌ Gagal ambil data manga, coba lagi');
            }
            return;
        }

        // ════════════════════════════════════════════════════
        //  ─────────────── IMAGE FEATURES ───────────────────
        // ════════════════════════════════════════════════════

        // ── .grayscale — convert gambar ke hitam putih ───────
        if (lower === '.grayscale') {
            const imgFile = await getImageFromMsg(message);
            if (!imgFile) return message.reply('Reply atau kirim foto dulu');
            await message.reply('⬛ Proses grayscale...');
            const outFile = tmpFile('jpg');
            try {
                // pakai ffmpeg: force grayscale
                execSync(`ffmpeg -y -i "${imgFile}" -vf "hue=s=0" "${outFile}"`);
                await client.sendMessage(message.from, MessageMedia.fromFilePath(outFile), { caption: '⬛ Done! Foto udah jadi hitam putih' });
            } finally {
                if (fs.existsSync(imgFile))  fs.unlinkSync(imgFile);
                if (fs.existsSync(outFile)) fs.unlinkSync(outFile);
            }
            return;
        }

        // ── .caption <teks> — tambah teks meme style ─────────
        if (lower.startsWith('.caption ')) {
            const captionText = text.slice(9).trim();
            if (!captionText) return message.reply('Contoh: .caption teks kamu disini (sambil reply foto)');

            const imgFile = await getImageFromMsg(message);
            if (!imgFile) return message.reply('Reply atau kirim foto dulu bro');
            await message.reply('✍️ Proses caption...');

            const outFile = tmpFile('jpg');
            try {
                // Pakai ffmpeg drawtext: font putih dengan outline hitam di bagian bawah
                // Escape karakter khusus untuk ffmpeg
                const escapedText = captionText
                    .replace(/\\/g, '\\\\')
                    .replace(/'/g, "\\'")
                    .replace(/:/g, '\\:')
                    .replace(/\[/g, '\\[')
                    .replace(/\]/g, '\\]');

                execSync(
                    `ffmpeg -y -i "${imgFile}" ` +
                    `-vf "drawtext=text='${escapedText}':` +
                    `fontsize=48:fontcolor=white:` +
                    `borderw=3:bordercolor=black:` +
                    `x=(w-text_w)/2:y=h-th-20:` +
                    `font=DejaVuSans-Bold" ` +
                    `"${outFile}"`
                );
                await client.sendMessage(message.from, MessageMedia.fromFilePath(outFile), { caption: '✍️ Caption ditambahkan!' });
            } finally {
                if (fs.existsSync(imgFile))  fs.unlinkSync(imgFile);
                if (fs.existsSync(outFile)) fs.unlinkSync(outFile);
            }
            return;
        }

        // ── .removebg ────────────────────────────────────────────────
if (lower === '.removebg') {
    if (!REMOVE_BG_API_KEY || REMOVE_BG_API_KEY === 'ISI_API_KEY_KAMU_DISINI') {
        return message.reply('❌ API key belum diisi!');
    }

    const imgFile = await getImageFromMsg(message);
    if (!imgFile) return message.reply('Reply atau kirim foto dulu');
    await message.reply('✂️ Hapus background... sabar ya');

    const outFile = tmpFile('png');
    try {
        const imageBuffer = fs.readFileSync(imgFile);
        const base64Image = imageBuffer.toString('base64');

        const res = await axios({
            method: 'post',
            url: 'https://api.remove.bg/v1.0/removebg',
            data: {
                image_file_b64: base64Image,
                size: 'auto'
            },
            headers: {
                'X-Api-Key': REMOVE_BG_API_KEY,
                'Content-Type': 'application/json'
            },
            responseType: 'arraybuffer',
            timeout: 30000
        });

        fs.writeFileSync(outFile, res.data);
        await client.sendMessage(message.from, MessageMedia.fromFilePath(outFile), {
            caption: '✅ Background berhasil dihapus!'
        });

    } catch (e) {
        const status = e.response?.status;
        const body   = e.response?.data ? Buffer.from(e.response.data).toString() : '';
        console.error('[REMOVEBG]', status, body);

        if (status === 402) return message.reply('❌ Kredit remove.bg habis (50/bulan)');
        if (status === 403) return message.reply('❌ API key ditolak');
        if (status === 400) return message.reply('❌ Format gambar tidak didukung');
        return message.reply(`❌ Error ${status ?? 'unknown'}: ${body.slice(0,100)}`);
    } finally {
        if (fs.existsSync(imgFile))  fs.unlinkSync(imgFile);
        if (fs.existsSync(outFile)) fs.unlinkSync(outFile);
    }
    return;
}

        // ════════════════════════════════════════════════════
        //  TAGALL
        // ════════════════════════════════════════════════════
        if (lower === '.tagall') {
            if (!chat.isGroup) return message.reply('Fitur ini khusus grup');
            const mentions = [];
            let txt = '📢 *Hei semua!*\n\n';
            for (const p of chat.participants) {
                const c = await client.getContactById(p.id._serialized);
                mentions.push(c);
                txt += `@${p.id.user} `;
            }
            return chat.sendMessage(txt, { mentions });
        }

        // ════════════════════════════════════════════════════
        //  ANTI-LINK
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.antilink ')) {
            if (!chat.isGroup) return message.reply('Khusus grup');
            const arg = lower.split(' ')[1];
            const gid = chat.id._serialized;
            if (arg === 'on')  { ANTI_LINK_GROUPS.add(gid);    return message.reply('✅ Anti-link *AKTIF*'); }
            if (arg === 'off') { ANTI_LINK_GROUPS.delete(gid); return message.reply('❌ Anti-link *NONAKTIF*'); }
            return message.reply('Contoh: .antilink on / .antilink off');
        }

        // ════════════════════════════════════════════════════
        //  TEBAK ANGKA
        // ════════════════════════════════════════════════════
        if (lower === '.tebak') {
            global.tebakGames[message.from] = { angka: Math.floor(Math.random()*100)+1, attempts: 0 };
            return message.reply('🎲 *TEBAK ANGKA*\nAku pilih angka 1–100, tebak!\nKetik *.stoptebak* buat berhenti');
        }
        if (lower === '.stoptebak' && global.tebakGames[message.from]) {
            const { angka } = global.tebakGames[message.from];
            delete global.tebakGames[message.from];
            return message.reply(`🏳️ Berhenti. Angkanya *${angka}*`);
        }
        if (global.tebakGames[message.from] && /^\d+$/.test(lower)) {
            const game = global.tebakGames[message.from];
            const n    = parseInt(lower);
            game.attempts++;
            if (n === game.angka)    { delete global.tebakGames[message.from]; return message.reply(`🎉 BENER! Angkanya *${game.angka}* — ${game.attempts} kali tebak!`); }
            else if (n < game.angka) return message.reply(`📈 Terlalu kecil! (ke-${game.attempts})`);
            else                     return message.reply(`📉 Terlalu besar! (ke-${game.attempts})`);
        }

        // ════════════════════════════════════════════════════
        //  SUIT
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.suit ')) {
            const pUser = lower.split(' ')[1];
            const valid = ['gunting','batu','kertas'];
            if (!valid.includes(pUser)) return message.reply('Pilihan: gunting / batu / kertas\nContoh: .suit batu');
            const pBot  = valid[Math.floor(Math.random()*3)];
            const emoji = { gunting:'✂️', batu:'🪨', kertas:'📄' };
            const menang = (pUser==='gunting'&&pBot==='kertas') || (pUser==='batu'&&pBot==='gunting') || (pUser==='kertas'&&pBot==='batu');
            const hasil  = pUser===pBot ? '🤝 *SERI!*' : menang ? '🎉 *KAMU MENANG!*' : '😅 *BOT MENANG!*';
            return message.reply(`✂️🪨📄 *SUIT*\n━━━━━━━━━━━\nKamu : ${emoji[pUser]} ${pUser}\nBot  : ${emoji[pBot]} ${pBot}\n━━━━━━━━━━━\n${hasil}`);
        }

        // ════════════════════════════════════════════════════
        //  RANDOM WAIFU
        // ════════════════════════════════════════════════════
        if (lower === '.randomwaifu') {
            await message.reply('🎀 Loading waifu...');
            const cats = ['waifu','neko','shinobu','megumin','awoo'];
            const cat  = cats[Math.floor(Math.random()*cats.length)];
            const res  = await axios.get(`https://api.waifu.pics/sfw/${cat}`);
            const url  = res.data.url;
            const ext  = url.split('.').pop().split('?')[0] || 'jpg';
            const file = tmpFile(ext);
            try {
                const img = await axios.get(url, { responseType: 'arraybuffer' });
                fs.writeFileSync(file, img.data);
                await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                    caption: `🎀 *Random Waifu* — _${cat}_\n.randomwaifu lagi untuk yang lain~`
                });
            } finally {
                if (fs.existsSync(file)) fs.unlinkSync(file);
            }
            return;
        }

        // ════════════════════════════════════════════════════════════
//  MEME — pakai subreddit lokal Indonesia
// ════════════════════════════════════════════════════════════
if (lower === '.meme') {
    await message.reply('😂 Nyari meme...');

    // Pilih random dari subreddit Indonesia / Asia
    const subreddits = ['indonesia', 'AseanMemes', 'memeindonesia'];
    const sub = subreddits[Math.floor(Math.random() * subreddits.length)];

    try {
        const res = await axios.get(`https://meme-api.com/gimme/${sub}`, { timeout: 10000 });

        // Kalau nsfw atau bukan gambar, fallback ke subreddit lain
        if (res.data.nsfw || !res.data.url?.match(/\.(jpg|jpeg|png|gif)$/i)) {
            const fallback = await axios.get('https://meme-api.com/gimme/dankmemes', { timeout: 10000 });
            const url  = fallback.data.url;
            const ext  = url.split('.').pop().split('?')[0] || 'jpg';
            const file = tmpFile(ext);
            try {
                const img = await axios.get(url, { responseType: 'arraybuffer' });
                fs.writeFileSync(file, img.data);
                await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                    caption: `😂 *${fallback.data.title}*\n👍 ${fallback.data.ups} upvotes`
                });
            } finally {
                if (fs.existsSync(file)) fs.unlinkSync(file);
            }
            return;
        }

        const url  = res.data.url;
        const ext  = url.split('.').pop().split('?')[0] || 'jpg';
        const file = tmpFile(ext);
        try {
            const img = await axios.get(url, { responseType: 'arraybuffer' });
            fs.writeFileSync(file, img.data);
            await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                caption: `😂 *${res.data.title}*\n👍 ${res.data.ups} upvotes | r/${sub}`
            });
        } finally {
            if (fs.existsSync(file)) fs.unlinkSync(file);
        }
    } catch {
        // Fallback kalau subreddit error
        const res  = await axios.get('https://meme-api.com/gimme', { timeout: 10000 });
        const url  = res.data.url;
        const ext  = url.split('.').pop().split('?')[0] || 'jpg';
        const file = tmpFile(ext);
        try {
            const img = await axios.get(url, { responseType: 'arraybuffer' });
            fs.writeFileSync(file, img.data);
            await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                caption: `😂 *${res.data.title}*`
            });
        } finally {
            if (fs.existsSync(file)) fs.unlinkSync(file);
        }
    }
    return;
}

// ════════════════════════════════════════════════════════════
//  JOKES — pakai Candaan API (jokes receh Indonesia)
// ════════════════════════════════════════════════════════════
if (lower === '.jokes') {
    try {
        // Candaan API - jokes receh bahasa Indonesia
        const res  = await axios.get('https://candaan-api.vercel.app/api/text/random', { timeout: 8000 });
        const joke = typeof res.data === 'string' ? res.data : res.data?.data;
        if (!joke) throw new Error('empty');
        return message.reply(`😄 *Jokes Receh* 🤣\n━━━━━━━━━━━\n${joke}`);
    } catch {
        // Fallback: jokes bapak-bapak hardcoded kalau API down
        const fallback = [
            'Kenapa kalau naik motor maunya ketawa terus?\nKarena duduknya di atas jokes! 😂',
            'Benda apa yang kalau dibalik selalu rusak?\nKasur! 😅',
            'Buah apa yang nggak segar?\nAlpucat! 😆',
            'Kenapa kerang adanya di laut?\nKarena kalau di darat nanti jadi kering! 🤣',
            'Kalo mau manasin motor enaknya direbus apa digoreng? 😂',
            'Jangan panggil aku mantan. Sebut saja aku alumni. Siapa tahu kita bisa reuni 😁',
            'Pisang kalau masih panas namanya apa? Hihang Hoheng 😂',
            'Manusia boleh berencana, tapi saldo yang menentukan 🤣',
        ];
        const joke = fallback[Math.floor(Math.random() * fallback.length)];
        return message.reply(`😄 *Jokes Receh* 🤣\n━━━━━━━━━━━\n${joke}`);
    }
}

        // ════════════════════════════════════════════════════
        //  QUOTES
        // ════════════════════════════════════════════════════
        if (lower === '.quotes') {
            const res = await axios.get('https://zenquotes.io/api/random');
            const q   = res.data[0];
            return message.reply(`💬 *Quote of the Moment*\n━━━━━━━━━━━\n"${q.q}"\n\n— _${q.a}_`);
        }

        // ════════════════════════════════════════════════════
        //  GITHUB USER
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.githubuser ')) {
            const username = text.split(' ')[1];
            if (!username) return message.reply('Contoh: .githubuser torvalds');
            try {
                const res  = await axios.get(`https://api.github.com/users/${username}`);
                const u    = res.data;
                const file = tmpFile('jpg');
                try {
                    const img = await axios.get(u.avatar_url, { responseType: 'arraybuffer' });
                    fs.writeFileSync(file, img.data);
                    await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                        caption: `🐙 *GitHub: ${u.login}*\n━━━━━━━━━━━━━━━\n👤 Nama    : *${u.name ?? '-'}*\n📍 Lokasi  : *${u.location ?? '-'}*\n🏢 Company : *${u.company ?? '-'}*\n📦 Repos   : *${u.public_repos}*\n👥 Follower: *${u.followers}*\n🔗 ${u.html_url}`
                    });
                } finally {
                    if (fs.existsSync(file)) fs.unlinkSync(file);
                }
            } catch (e) {
                if (e.response?.status === 404) return message.reply(`❌ User "${username}" tidak ditemukan`);
                throw e;
            }
            return;
        }

// ════════════════════════════════════════════════════════════
//  .crypto <kode> — Harga crypto real-time
//  Contoh: .crypto btc / .crypto eth / .crypto bnb
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.crypto ')) {
    const kode = lower.split(' ')[1]?.trim();
    if (!kode) return message.reply('Contoh: .crypto btc\nAtau: .crypto eth, .crypto bnb, .crypto sol');

    await message.reply('📊 Ambil data crypto...');

    try {
        // CoinGecko API - gratis no key
        const searchUrl = `https://api.coingecko.com/api/v3/search?query=${kode}`;
        const searchData = JSON.parse(require('child_process').execSync(
            `curl -s -m 15 -H "Accept: application/json" "${searchUrl}"`,
            { maxBuffer: 5 * 1024 * 1024 }
        ).toString());

        const coin = searchData?.coins?.[0];
        if (!coin) return message.reply(`❌ Crypto "${kode.toUpperCase()}" tidak ditemukan`);

        const coinId = coin.id;
        const priceUrl = `https://api.coingecko.com/api/v3/coins/${coinId}?localization=false&tickers=false&community_data=false&developer_data=false`;
        const data = JSON.parse(require('child_process').execSync(
            `curl -s -m 15 -H "Accept: application/json" "${priceUrl}"`,
            { maxBuffer: 5 * 1024 * 1024 }
        ).toString());

        const usd    = data.market_data?.current_price?.usd;
        const idr    = data.market_data?.current_price?.idr;
        const chg24  = data.market_data?.price_change_percentage_24h;
        const chg7d  = data.market_data?.price_change_percentage_7d;
        const cap    = data.market_data?.market_cap?.usd;
        const vol    = data.market_data?.total_volume?.usd;
        const high24 = data.market_data?.high_24h?.usd;
        const low24  = data.market_data?.low_24h?.usd;
        const rank   = data.market_cap_rank;

        const chg24Str = chg24 ? (chg24 > 0 ? `+${chg24.toFixed(2)}%` : `${chg24.toFixed(2)}%`) : '-';
        const chg7dStr = chg7d ? (chg7d > 0 ? `+${chg7d.toFixed(2)}%` : `${chg7d.toFixed(2)}%`) : '-';
        const chgEmoji = chg24 > 0 ? '📈' : '📉';

        return message.reply(
`💰 *${data.name} (${data.symbol?.toUpperCase()})*
━━━━━━━━━━━━━━━
💵 Harga USD : *${formatPrice(usd)}*
🇮🇩 Harga IDR : *Rp ${idr?.toLocaleString('id-ID') ?? '-'}*
${chgEmoji} 24 Jam    : *${chg24Str}*
📅 7 Hari    : *${chg7dStr}*
━━━━━━━━━━━━━━━
🔺 High 24h  : ${formatPrice(high24)}
🔻 Low 24h   : ${formatPrice(low24)}
📊 Market Cap: $${formatNumber(cap)}
💹 Volume 24h: $${formatNumber(vol)}
🏆 Rank      : #${rank ?? '-'}
━━━━━━━━━━━━━━━
🕐 ${new Date().toLocaleString('id-ID')}
_Ketik .prediksi ${kode} untuk analisis teknikal_`
        );
    } catch(e) {
        console.error('[CRYPTO]', e.message);
        return message.reply('❌ Gagal ambil data crypto, coba lagi');
    }
}

// ════════════════════════════════════════════════════════════
//  .cryptotrend — Top 10 crypto naik/turun hari ini
// ════════════════════════════════════════════════════════════
if (lower === '.cryptotrend') {
    await message.reply('📊 Ambil data trend crypto...');

    try {
        const url  = `https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=20&page=1&price_change_percentage=24h`;
        const data = JSON.parse(require('child_process').execSync(
            `curl -s -m 15 -H "Accept: application/json" "${url}"`,
            { maxBuffer: 5 * 1024 * 1024 }
        ).toString());

        if (!data?.length) return message.reply('❌ Gagal ambil data');

        // Sort by 24h change
        const sorted = [...data].sort((a, b) =>
            (b.price_change_percentage_24h ?? -999) - (a.price_change_percentage_24h ?? -999)
        );

        const top5up   = sorted.slice(0, 5);
        const top5down = sorted.slice(-5).reverse();

        let reply = `📊 *Crypto Trend Hari Ini*\n━━━━━━━━━━━━━━━\n\n`;

        reply += `*🟢 TOP 5 NAIK*\n`;
        top5up.forEach((c, i) => {
            const chg = c.price_change_percentage_24h?.toFixed(2) ?? '-';
            reply += `*${i+1}.* ${c.name} (${c.symbol?.toUpperCase()})\n`;
            reply += `    💵 ${formatPrice(c.current_price)} | 📈 +${chg}%\n\n`;
        });

        reply += `*🔴 TOP 5 TURUN*\n`;
        top5down.forEach((c, i) => {
            const chg = c.price_change_percentage_24h?.toFixed(2) ?? '-';
            reply += `*${i+1}.* ${c.name} (${c.symbol?.toUpperCase()})\n`;
            reply += `    💵 ${formatPrice(c.current_price)} | 📉 ${chg}%\n\n`;
        });

        reply += `🕐 ${new Date().toLocaleString('id-ID')}`;
        return message.reply(reply.trim());
    } catch(e) {
        console.error('[CRYPTOTREND]', e.message);
        return message.reply('❌ Gagal ambil data, coba lagi');
    }
}

// ════════════════════════════════════════════════════════════
//  .prediksi <kode> — Analisis teknikal crypto (MA+RSI+MACD)
//  Contoh: .prediksi btc
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.prediksi ')) {
    const kode = lower.split(' ')[1]?.trim();
    if (!kode) return message.reply('Contoh: .prediksi btc');

    await message.reply('🔍 Analisis teknikal... (ini butuh beberapa detik)');

    try {
        // Cari coin ID dulu
        const searchData = JSON.parse(require('child_process').execSync(
            `curl -s -m 15 -H "Accept: application/json" "https://api.coingecko.com/api/v3/search?query=${kode}"`,
            { maxBuffer: 5 * 1024 * 1024 }
        ).toString());

        const coin = searchData?.coins?.[0];
        if (!coin) return message.reply(`❌ Crypto "${kode.toUpperCase()}" tidak ditemukan`);

        const coinId   = coin.id;
        const coinName = coin.name;
        const coinSym  = coin.symbol?.toUpperCase();

        // Ambil data historis 30 hari (daily)
        const histUrl  = `https://api.coingecko.com/api/v3/coins/${coinId}/market_chart?vs_currency=usd&days=30&interval=daily`;
        const histData = JSON.parse(require('child_process').execSync(
            `curl -s -m 20 -H "Accept: application/json" "${histUrl}"`,
            { maxBuffer: 10 * 1024 * 1024 }
        ).toString());

        const prices = histData?.prices?.map(p => p[1]);
        if (!prices || prices.length < 15) return message.reply('❌ Data historis tidak cukup untuk analisis');

        const currentPrice = prices[prices.length - 1];

        // Hitung indikator
        const ma7    = calcMA(prices, 7);
        const ma25   = calcMA(prices, 25);
        const rsi    = calcRSI(prices, 14);
        const macd   = calcMACD(prices);

        // Generate sinyal
        const { finalSignal, emoji, signals } = generateSignal(rsi, macd, ma7, ma25, currentPrice);

        // Hitung support & resistance sederhana
        const recent  = prices.slice(-14);
        const support = Math.min(...recent);
        const resist  = Math.max(...recent);

        // Persentase dari support & resistance
        const toResist  = ((resist - currentPrice) / currentPrice * 100).toFixed(1);
        const toSupport = ((currentPrice - support) / currentPrice * 100).toFixed(1);

        let reply =
`🔮 *Prediksi ${coinName} (${coinSym})*
━━━━━━━━━━━━━━━
💵 Harga Saat Ini : *${formatPrice(currentPrice)}*
━━━━━━━━━━━━━━━
📊 *INDIKATOR TEKNIKAL*

📈 MA 7  : ${formatPrice(ma7)}
📈 MA 25 : ${formatPrice(ma25)}
⚡ RSI   : ${rsi?.toFixed(1) ?? '-'}
🌊 MACD  : ${macd?.toFixed(4) ?? '-'}
━━━━━━━━━━━━━━━
🎯 *ANALISIS*
${signals.map(s => `• ${s}`).join('\n')}
━━━━━━━━━━━━━━━
📍 *SUPPORT & RESISTANCE (14 hari)*
🔻 Support  : ${formatPrice(support)} (-${toSupport}%)
🔺 Resistance: ${formatPrice(resist)} (+${toResist}%)
━━━━━━━━━━━━━━━
${emoji} *SINYAL: ${finalSignal}*
━━━━━━━━━━━━━━━
⚠️ *DISCLAIMER*
_Ini bukan saran investasi. Prediksi berdasarkan analisis teknikal historis dan TIDAK menjamin keakuratan. Selalu lakukan riset mandiri (DYOR) sebelum berinvestasi. Investasi crypto memiliki risiko tinggi._

🕐 ${new Date().toLocaleString('id-ID')}`;

        return message.reply(reply);
    } catch(e) {
        console.error('[PREDIKSI]', e.message);
        return message.reply('❌ Gagal analisis, coba lagi');
    }
}

// ════════════════════════════════════════════════════════════
//  .saham <kode> — Harga saham IDX real-time
//  Contoh: .saham BBCA / .saham TLKM / .saham GOTO
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.saham ')) {
    const kode = text.split(' ')[1]?.trim().toUpperCase();
    if (!kode) return message.reply('Contoh: .saham BBCA\nKode IDX: BBCA, TLKM, BBRI, GOTO, ASII, dll');

    await message.reply('📊 Ambil data saham...');

    try {
        // Yahoo Finance API (no key needed)
        const ticker  = `${kode}.JK`; // .JK = Jakarta Stock Exchange
        const url     = `https://query1.finance.yahoo.com/v8/finance/chart/${ticker}?interval=1d&range=1mo`;
        const raw     = require('child_process').execSync(
            `curl -s -m 15 -H "User-Agent: Mozilla/5.0" -H "Accept: application/json" "${url}"`,
            { maxBuffer: 10 * 1024 * 1024 }
        ).toString();

        const data    = JSON.parse(raw);
        const result  = data?.chart?.result?.[0];
        if (!result) return message.reply(`❌ Saham "${kode}" tidak ditemukan di IDX`);

        const meta    = result.meta;
        const current = meta?.regularMarketPrice;
        const prev    = meta?.chartPreviousClose;
        const change  = current - prev;
        const changePct = (change / prev * 100);
        const high    = meta?.regularMarketDayHigh;
        const low     = meta?.regularMarketDayLow;
        const vol     = meta?.regularMarketVolume;
        const cap     = meta?.marketCap;

        const chgStr  = change > 0 ? `+${change.toFixed(0)}` : change.toFixed(0);
        const chgPctStr = changePct > 0 ? `+${changePct.toFixed(2)}%` : `${changePct.toFixed(2)}%`;
        const chgEmoji = change > 0 ? '📈' : '📉';

        // Ambil harga historis untuk analisis sederhana
        const closes  = result.indicators?.quote?.[0]?.close?.filter(Boolean) ?? [];
        const ma7     = calcMA(closes, 7);
        const rsi     = calcRSI(closes, 14);

        let sinyalStr = '';
        if (rsi) {
            if (rsi < 30)      sinyalStr = '🟢 *Oversold — Potensi Naik*';
            else if (rsi > 70) sinyalStr = '🔴 *Overbought — Potensi Turun*';
            else if (current > (ma7 ?? 0)) sinyalStr = '🟡 *Di atas MA7 — Tren Positif*';
            else               sinyalStr = '🟡 *Di bawah MA7 — Tren Negatif*';
        }

        return message.reply(
`📈 *Saham ${kode} (IDX)*
━━━━━━━━━━━━━━━
💰 Harga    : *Rp ${current?.toLocaleString('id-ID') ?? '-'}*
${chgEmoji} Perubahan : *${chgStr} (${chgPctStr})*
📊 Prev Close: Rp ${prev?.toLocaleString('id-ID') ?? '-'}
━━━━━━━━━━━━━━━
🔺 High     : Rp ${high?.toLocaleString('id-ID') ?? '-'}
🔻 Low      : Rp ${low?.toLocaleString('id-ID') ?? '-'}
📦 Volume   : ${vol?.toLocaleString('id-ID') ?? '-'}
💎 Market Cap: Rp ${cap ? (cap/1e12).toFixed(2)+'T' : '-'}
━━━━━━━━━━━━━━━
📊 MA 7     : Rp ${ma7?.toLocaleString('id-ID', {maximumFractionDigits:0}) ?? '-'}
⚡ RSI 14   : ${rsi?.toFixed(1) ?? '-'}
${sinyalStr ? sinyalStr + '\n' : ''}━━━━━━━━━━━━━━━
⚠️ _Bukan saran investasi. DYOR._
🕐 ${new Date().toLocaleString('id-ID')}`
        );
    } catch(e) {
        console.error('[SAHAM]', e.message);
        return message.reply('❌ Gagal ambil data saham, coba lagi\nPastikan kode saham benar (contoh: BBCA, TLKM, BBRI)');
    }
}

        // ════════════════════════════════════════════════════
        //  PASSWORD
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.password')) {
            const pjg = parseInt(lower.split(' ')[1]) || 16;
            if (pjg < 4 || pjg > 64) return message.reply('Panjang 4–64 karakter');
            const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+[]{}';
            let pass = '';
            for (let i = 0; i < pjg; i++) pass += chars[Math.floor(Math.random()*chars.length)];
            return message.reply(`🔑 *Password Random (${pjg} karakter)*\n\`\`\`${pass}\`\`\``);
        }

        // ════════════════════════════════════════════════════
        //  KALKULATOR
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.kalkulator ')) {
            const ekspresi = text.slice(12).trim();
            if (!ekspresi) return message.reply('Contoh: .kalkulator 12 * (3 + 4)');
            if (!/^[\d\s+\-*/().^%]+$/.test(ekspresi)) return message.reply('❌ Hanya boleh: angka + - * / % ^ ()');
            try {
                const result = Function(`"use strict"; return (${ekspresi.replace(/\^/g,'**')})`)();
                return message.reply(`🧮 *Kalkulator*\n━━━━━━━━━━━\n${ekspresi}\n= *${result}*`);
            } catch {
                return message.reply('❌ Ekspresi tidak valid');
            }
        }

// ════════════════════════════════════════════════════════════
//  .rvo — Reveal View Once
// ════════════════════════════════════════════════════════════
if (lower === '.rvo') {
    if (!message.hasQuotedMsg) return message.reply('Reply pesan view once dulu, lalu ketik .rvo');

    const quoted = await message.getQuotedMessage();

    console.log('[RVO DEBUG]', JSON.stringify({
    type: quoted.type,
    isViewOnce: quoted._data?.isViewOnce,
    viewOnce: quoted._data?.viewOnce,
    keys: Object.keys(quoted._data || {}).filter(k => k.toLowerCase().includes('view'))
}));

if (!quoted._data?.isViewOnce && !quoted._data?.viewOnce && quoted.type !== 'image' && quoted.type !== 'video') {
    return message.reply('❌ Itu bukan pesan view once');
}

    await message.reply('🔓 Ekstrak view once...');

    try {
        quoted._data.isViewOnce = false;
        quoted._data.viewOnce   = false;

        const media = await quoted.downloadMedia();

        if (!media || !media.data) {
            return message.reply('❌ Gagal ekstrak.\n\nKemungkinan:\n• Foto sudah expired/dibuka\n• WhatsApp sudah patch metode ini');
        }

        const ext  = media.mimetype.includes('video') ? 'mp4' : 'jpg';
        const file = tmpFile(ext);

        try {
            fs.writeFileSync(file, Buffer.from(media.data, 'base64'));
            await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                caption: `🔓 *View Once berhasil diekstrak!*\n_Jaga privasi orang lain ya_ 🙏`
            });
        } finally {
            if (fs.existsSync(file)) fs.unlinkSync(file);
        }

    } catch(e) {
        console.error('[RVO]', e.message);
        return message.reply('❌ Gagal: ' + e.message);
    }
    return;
}

    // ===== ON OFF =====
    if (lower === '.chizu on') {
        autoAI = true;
        return message.reply('✅ Chizu aktif');
    }

    if (lower === '.chizu off') {
        autoAI = false;
        return message.reply('❌ Chizu mati');
    }

    if (lower === '.resetai') {
        aiMemory.delete(message.from);
        return message.reply('🧠 Memory direset');
    }

const isGroup = message.from.includes('@g.us');

// cek ada kata "chizu"
const isCallChizu = text.toLowerCase().includes('chizu');

// cek reply ke bot
const isReplyToBot = message.hasQuotedMsg
    ? (await message.getQuotedMessage()).fromMe
    : false;

    // ===== AUTO AI =====
    if (
        autoAI &&
        !message.fromMe &&
        !text.startsWith('.') &&
        (isCallChizu || isReplyToBot)
    ) {
        try {
            const userId = message.from;

            // Filter pesan tidak penting
            if (text.length < 3 || text.length > 500) return;

            // Cooldown 8 detik per user
            const now = Date.now();
            if (cooldown.has(userId) && now - cooldown.get(userId) < 8000) return;
            cooldown.set(userId, now);

            // Simpan pesan user ke memory
            pushMemory(userId, 'user', text);

            // Generate response dengan multi-model fallback
            // Cek apakah ada kata "vois" di pesan
const mintaVoice = lower.includes('vois');

if (mintaVoice) {
    // Hapus kata "vois" dari teks yang dikirim ke AI
    const tekstanpaVois = text.replace(/vois/gi, '').trim();

    // Generate response Chizu seperti biasa
    pushMemory(userId, 'user', tekstanpaVois);
    const reply = await generateChizu(userId, tekstanpaVois);
    if (!reply) return;
    pushMemory(userId, 'assistant', reply);

    // Kirim sebagai voice note
    const wav = tmpFile('wav');
    const ogg = tmpFile('ogg');
    try {
	const styledReply = `[Speak in a soft, and smooth female voice. Tone is calm and warm, like a Indoenisan young HIghschool quiet girl talking casually. Pace is rather fast, indifferent and relaxed. Pronunciation is clear and delicate. Never loud or assertive.] ${reply}`;
        const result = await ai.models.generateContent({
            model: 'gemini-2.5-flash-preview-tts',
            contents: [{ role: 'user', parts: [{ text: styledReply }] }],
            config: {
                responseModalities: ['AUDIO'],
                speechConfig: {
                    voiceConfig: {
                        prebuiltVoiceConfig: {
                            voiceName: 'Leda' // suara cewek cool ala Chizu
                        }
                    }
                }
            }
        });

        const audioData = result.candidates?.[0]?.content?.parts?.[0]?.inlineData?.data;
        if (!audioData) throw new Error('Tidak ada audio');

        fs.writeFileSync(wav, Buffer.from(audioData, 'base64'));
        execSync(`ffmpeg -y -f s16le -ar 24000 -ac 1 -i "${wav}" -c:a libopus -b:a 32k -ar 48000 "${ogg}"`, { timeout: 15000 });

        const media = new MessageMedia(
            'audio/ogg; codecs=opus',
            fs.readFileSync(ogg).toString('base64'),
            'voice.ogg'
        );
        await client.sendMessage(message.from, media, { sendAudioAsVoice: true });

    } catch(e) {
        console.error('[CHIZU VOICE]', e.message);
        // Fallback kirim teks kalau TTS gagal
        await message.reply(reply);
    } finally {
        if (fs.existsSync(wav)) fs.unlinkSync(wav);
        if (fs.existsSync(ogg)) fs.unlinkSync(ogg);
    }
    return; // stop, jangan lanjut ke reply teks biasa
}

// Kalau tidak ada "vois", reply teks seperti biasa
const reply = await generateChizu(userId, text);
if (!reply) return;
pushMemory(userId, 'assistant', reply);
await message.reply(reply);

        } catch (e) {
            console.error('[CHIZU FINAL]', e.message);
        }
    }

// ════════════════════════════════════════════════════════════
//  .ttdl <url> — Download TikTok tanpa watermark
//  Pakai tikwm.com API (gratis, no key)
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.ttdl ')) {
    const url = text.split(' ')[1]?.trim();
    if (!url) return message.reply('Contoh: .ttdl https://vt.tiktok.com/xxxxx');

    await message.reply('⏳ Download TikTok...');

    try {
        // resolve short link
        let finalUrl = url;
        if (url.includes('vt.tiktok') || url.includes('vm.tiktok')) {
            const res = await axios.get(url, { maxRedirects: 5 });
            finalUrl = res.request.res.responseUrl;
        }

        const api = await axios.post('https://www.tikwm.com/api/', new URLSearchParams({
            url: finalUrl,
            hd: 1
        }), {
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            timeout: 20000
        });

        const data = api.data;

        if (!data || data.code !== 0) {
            return message.reply('❌ Gagal ambil video TikTok');
        }

        const videoUrl = data.data.hdplay || data.data.play;
        if (!videoUrl) return message.reply('❌ Video tidak tersedia');

        const file = tmpFile('mp4');
        const stream = await axios.get(videoUrl, { responseType: 'arraybuffer' });
        fs.writeFileSync(file, stream.data);

        await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
            caption: `✅ TikTok berhasil didownload`
        });

        fs.unlinkSync(file);

    } catch (e) {
        console.error('[TTDL FIX]', e.message);
        return message.reply('❌ Error TikTok');
    }
}


// ════════════════════════════════════════════════════════════
//  .igdl <url> — Download Instagram foto/video/reels
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.igdl ')) {
    const url = text.split(' ')[1]?.trim();
    if (!url) return message.reply('Contoh: .igdl https://www.instagram.com/p/xxxxx/\nAtau: .igdl https://www.instagram.com/reel/xxxxx/');
    if (!url.includes('instagram.com')) return message.reply('❌ URL harus dari Instagram');

    await message.reply('⏳ Download Instagram... (butuh beberapa detik)');

    try {
        const fileVideo = tmpFile('mp4');
        const fileImg   = tmpFile('jpg');
        let success = false;

        // Coba pakai yt-dlp untuk video/reels
        try {
            await ytDlp.execPromise([
                url,
                '-f', 'best[ext=mp4]/best',
                '-o', fileVideo,
                '--no-playlist',
                '--no-warnings',
                '--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            ]);

            if (fs.existsSync(fileVideo) && fs.statSync(fileVideo).size > 1000) {
                await client.sendMessage(message.from, MessageMedia.fromFilePath(fileVideo), {
                    caption: '✅ Instagram video berhasil didownload!'
                });
                success = true;
            }
        } catch (_) {}

        // Fallback: coba ambil gambar
        if (!success) {
            const { execSync } = require('child_process');
            const shortcode = url.match(/\/(p|reel|tv)\/([A-Za-z0-9_-]+)/)?.[2];

            if (shortcode) {
                const apiRes = execSync(
                    `curl -s -m 15 ` +
                    `-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" ` +
                    `"https://www.instagram.com/p/${shortcode}/?__a=1&__d=dis"`,
                    { maxBuffer: 5 * 1024 * 1024 }
                ).toString();

                try {
                    const data   = JSON.parse(apiRes);
                    const media  = data?.items?.[0];
                    const imgUrl = media?.image_versions2?.candidates?.[0]?.url
                                || media?.carousel_media?.[0]?.image_versions2?.candidates?.[0]?.url;

                    if (imgUrl) {
                        execSync(`curl -s -m 30 -L -o "${fileImg}" "${imgUrl}"`, { maxBuffer: 20 * 1024 * 1024 });
                        if (fs.existsSync(fileImg) && fs.statSync(fileImg).size > 1000) {
                            await client.sendMessage(message.from, MessageMedia.fromFilePath(fileImg), {
                                caption: '✅ Instagram foto berhasil didownload!'
                            });
                            success = true;
                        }
                    }
                } catch (_) {}
            }
        }

        if (!success) {
            return message.reply(
                '❌ Gagal download Instagram.\n\n' +
                'Kemungkinan:\n' +
                '• Akun private\n' +
                '• Konten butuh login\n' +
                '• URL tidak valid'
            );
        }

        if (fs.existsSync(fileVideo)) fs.unlinkSync(fileVideo);
        if (fs.existsSync(fileImg))   fs.unlinkSync(fileImg);

    } catch(e) {
        console.error('[IGDL]', e.message);
        return message.reply('❌ Gagal download Instagram: ' + e.message.slice(0, 100));
    }
    return;
}


// ════════════════════════════════════════════════════════════
//  .motivasi — Quote motivasi bahasa Indonesia
// ════════════════════════════════════════════════════════════
if (lower === '.motivasi') {
    const quotes = [
        { q: 'Jangan takut gagal. Kegagalan adalah awal dari kesuksesan.', a: 'Anonim' },
        { q: 'Mulailah dari mana kamu berada, gunakan apa yang kamu punya, lakukan apa yang kamu bisa.', a: 'Arthur Ashe' },
        { q: 'Orang yang luar biasa memiliki kebiasaan yang luar biasa.', a: 'Brian Tracy' },
        { q: 'Sukses adalah perjalanan, bukan tujuan.', a: 'Ben Sweetland' },
        { q: 'Jika kamu ingin hidup bahagia, ikatlah pada tujuan, bukan pada orang atau benda.', a: 'Albert Einstein' },
        { q: 'Berani bermimpi, berani berjuang, berani menang.', a: 'Bung Karno' },
        { q: 'Kerja keras mengalahkan bakat ketika bakat tidak mau bekerja keras.', a: 'Tim Notke' },
        { q: 'Setiap hari adalah kesempatan baru untuk menjadi versi terbaik dirimu.', a: 'Anonim' },
        { q: 'Ribuan perjalanan dimulai dari satu langkah kecil.', a: 'Lao Tzu' },
        { q: 'Yang membedakan orang sukses adalah mereka terus mencoba meski sudah gagal berkali-kali.', a: 'Anonim' },
        { q: 'Hidup ini seperti naik sepeda. Agar tetap seimbang, kamu harus terus bergerak.', a: 'Albert Einstein' },
        { q: 'Jangan menghitung hari-harimu, tapi buatlah setiap harimu berarti.', a: 'Muhammad Ali' },
        { q: 'Percayalah pada dirimu sendiri dan semua yang kamu miliki.', a: 'Christian D. Larson' },
        { q: 'Kemarin adalah sejarah, besok adalah misteri, hari ini adalah anugerah.', a: 'Eleanor Roosevelt' },
        { q: 'Kamu tidak harus hebat untuk memulai, tapi kamu harus memulai untuk menjadi hebat.', a: 'Zig Ziglar' },
        { q: 'Jangan pernah menyerah karena hal besar membutuhkan waktu.', a: 'Anonim' },
        { q: 'Impianmu tidak memiliki batas waktu. Teruslah berjuang.', a: 'Anonim' },
        { q: 'Kesuksesan bukan milik orang yang pintar saja, tapi milik orang yang tidak pernah berhenti berusaha.', a: 'Anonim' },
        { q: 'Satu-satunya cara untuk melakukan pekerjaan hebat adalah mencintai apa yang kamu lakukan.', a: 'Steve Jobs' },
        { q: 'Bangun pagi, bekerja keras, berikan segalamu. Yang lain akan mengikuti.', a: 'Joel Osteen' },
    ];

    const pick = quotes[Math.floor(Math.random() * quotes.length)];

    return message.reply(
`💪 *Motivasi Hari Ini*
━━━━━━━━━━━━━━━
_"${pick.q}"_

— *${pick.a}*
━━━━━━━━━━━━━━━
🕐 ${new Date().toLocaleString('id-ID', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })}`
    );
}


// ════════════════════════════════════════════════════════════
//  .zodiak <tanggal lahir> — Info zodiak + ramalan hari ini
//  Contoh: .zodiak 15 Agustus / .zodiak 15/08
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.zodiak ')) {
    const input = text.slice(8).trim();
    if (!input) return message.reply('Contoh: .zodiak 15 Agustus\nAtau: .zodiak 15/08');

    let day, month;

    const slashMatch = input.match(/^(\d{1,2})[\/\-](\d{1,2})$/);
    if (slashMatch) {
        day   = parseInt(slashMatch[1]);
        month = parseInt(slashMatch[2]);
    }

    if (!day) {
        const bulanMap = {
            'januari':1,'februari':2,'maret':3,'april':4,'mei':5,'juni':6,
            'juli':7,'agustus':8,'september':9,'oktober':10,'november':11,'desember':12,
            'jan':1,'feb':2,'mar':3,'apr':4,'jun':6,'jul':7,'agu':8,'sep':9,'okt':10,'nov':11,'des':12
        };
        const parts = input.toLowerCase().split(/\s+/);
        if (parts.length >= 2) {
            day   = parseInt(parts[0]);
            month = bulanMap[parts[1]];
        }
    }

    if (!day || !month || day < 1 || day > 31 || month < 1 || month > 12) {
        return message.reply('❌ Format tanggal tidak valid\nContoh: .zodiak 15 Agustus\nAtau: .zodiak 15/08');
    }

    const zodiakList = [
        { nama:'Capricorn',   emoji:'🐐', sm:12,sd:22, em:1, ed:19, el:'Bumi',  planet:'Saturnus' },
        { nama:'Aquarius',    emoji:'🏺', sm:1, sd:20, em:2, ed:18, el:'Udara', planet:'Uranus' },
        { nama:'Pisces',      emoji:'🐟', sm:2, sd:19, em:3, ed:20, el:'Air',   planet:'Neptunus' },
        { nama:'Aries',       emoji:'🐏', sm:3, sd:21, em:4, ed:19, el:'Api',   planet:'Mars' },
        { nama:'Taurus',      emoji:'🐂', sm:4, sd:20, em:5, ed:20, el:'Bumi',  planet:'Venus' },
        { nama:'Gemini',      emoji:'👯', sm:5, sd:21, em:6, ed:20, el:'Udara', planet:'Merkurius' },
        { nama:'Cancer',      emoji:'🦀', sm:6, sd:21, em:7, ed:22, el:'Air',   planet:'Bulan' },
        { nama:'Leo',         emoji:'🦁', sm:7, sd:23, em:8, ed:22, el:'Api',   planet:'Matahari' },
        { nama:'Virgo',       emoji:'👩', sm:8, sd:23, em:9, ed:22, el:'Bumi',  planet:'Merkurius' },
        { nama:'Libra',       emoji:'⚖️', sm:9, sd:23, em:10,ed:22, el:'Udara', planet:'Venus' },
        { nama:'Scorpio',     emoji:'🦂', sm:10,sd:23, em:11,ed:21, el:'Air',   planet:'Pluto' },
        { nama:'Sagittarius', emoji:'🏹', sm:11,sd:22, em:12,ed:21, el:'Api',   planet:'Jupiter' },
    ];

    let zodiak = null;
    for (const z of zodiakList) {
        if (z.sm > z.em) {
            if ((month === z.sm && day >= z.sd) || (month === z.em && day <= z.ed)) { zodiak = z; break; }
        } else {
            if ((month === z.sm && day >= z.sd) || (month === z.em && day <= z.ed) || (month > z.sm && month < z.em)) { zodiak = z; break; }
        }
    }

    if (!zodiak) return message.reply('❌ Tidak bisa menentukan zodiak');

    const idx = (new Date().getDate() + new Date().getMonth() + zodiakList.indexOf(zodiak)) % 6;

    const ramalanKerja = [
        'Produktivitas tinggi hari ini. Selesaikan tugas tertunda!',
        'Ada kesempatan baru di depan, jangan lewatkan!',
        'Fokus dan konsentrasi. Hasilmu akan memuaskan.',
        'Hati-hati dalam keputusan besar hari ini.',
        'Kolaborasi dengan rekan kerja membawa hasil terbaik.',
        'Istirahat sejenak, jangan terlalu keras pada dirimu.',
    ];
    const ramalanCinta = [
        'Hubunganmu semakin harmonis. Jaga komunikasi!',
        'Kejutan manis mungkin datang dari orang tersayang.',
        'Single? Hari ini bisa jadi hari spesial untuk bertemu seseorang.',
        'Luangkan waktu untuk orang-orang yang kamu cintai.',
        'Jangan ragu mengungkapkan perasaanmu.',
        'Sabar dan pengertian adalah kunci hari ini.',
    ];
    const ramalanKesehatan = [
        'Jaga pola makan dan istirahat yang cukup.',
        'Energi sedang bagus! Waktunya olahraga.',
        'Hindari begadang, tubuhmu butuh istirahat.',
        'Minum air yang cukup dan jaga kesehatan.',
        'Stres bisa pengaruhi kesehatanmu. Relaksasi!',
        'Kesehatan prima! Manfaatkan energimu dengan baik.',
    ];

    const bulanNama = ['','Januari','Februari','Maret','April','Mei','Juni','Juli','Agustus','September','Oktober','November','Desember'];

    return message.reply(
`${zodiak.emoji} *${zodiak.nama}*
📅 ${day} ${bulanNama[month]}
━━━━━━━━━━━━━━━
🌍 Elemen   : *${zodiak.el}*
🪐 Planet   : *${zodiak.planet}*
━━━━━━━━━━━━━━━
🔮 *Ramalan Hari Ini*

💼 Karir    : ${ramalanKerja[idx]}
❤️ Cinta    : ${ramalanCinta[idx]}
💪 Kesehatan: ${ramalanKesehatan[idx]}
━━━━━━━━━━━━━━━
🕐 ${new Date().toLocaleString('id-ID', { weekday:'long', day:'numeric', month:'long', year:'numeric' })}
_⚠️ Ramalan ini hanya untuk hiburan_`
    );
}

// ════════════════════════════════════════════════════════════
//  .tebakkata — Tebak kata dari hint (Wordle style)
// ════════════════════════════════════════════════════════════
if (!global.tebakKataGames) global.tebakKataGames = {};

if (lower === '.tebakkata') {
    await message.reply('🎮 Membuat soal tebak kata...');

    try {
        const prompt = `Buatkan 1 soal tebak kata bahasa Indonesia.
Format WAJIB (JSON only, no other text):
{
  "kata": "JAWABAN",
  "hint1": "hint pertama yang samar",
  "hint2": "hint kedua yang lebih jelas",
  "hint3": "hint ketiga yang hampir ketahuan",
  "kategori": "kategori kata"
}
Kata harus umum dikenal, 4-8 huruf, bahasa Indonesia.`;

        const raw  = await tanyaAI('Kamu generator soal tebak kata bahasa Indonesia. Selalu jawab dengan JSON valid saja.', prompt, 200);
        const json = raw.replace(/```json|```/g, '').trim();
        const data = JSON.parse(json);

        global.tebakKataGames[message.from] = {
            kata:     data.kata.toUpperCase(),
            hints:    [data.hint1, data.hint2, data.hint3],
            hintIdx:  0,
            attempts: 0,
            kategori: data.kategori
        };

        const game    = global.tebakKataGames[message.from];
        const blanks  = '_ '.repeat(game.kata.length).trim();

        return message.reply(
`🎮 *TEBAK KATA*
━━━━━━━━━━━━━━━
📂 Kategori : *${game.kategori}*
🔤 Kata     : *${blanks}* (${game.kata.length} huruf)
━━━━━━━━━━━━━━━
💡 Hint 1   : ${game.hints[0]}
━━━━━━━━━━━━━━━
Ketik jawabanmu!
_.hinttebak_ → hint berikutnya
_.stoptebakkata_ → menyerah`
        );

    } catch(e) {
        console.error('[TEBAKKATA]', e.message);
        return message.reply('❌ Gagal buat soal, coba lagi');
    }
}

if (lower === '.hinttebak' && global.tebakKataGames[message.from]) {
    const game = global.tebakKataGames[message.from];
    game.hintIdx++;
    if (game.hintIdx >= game.hints.length) {
        return message.reply('❌ Hint sudah habis! Coba tebak atau ketik _.stoptebakkata_');
    }
    return message.reply(`💡 *Hint ${game.hintIdx + 1}:* ${game.hints[game.hintIdx]}`);
}

if (lower === '.stoptebakkata' && global.tebakKataGames[message.from]) {
    const { kata } = global.tebakKataGames[message.from];
    delete global.tebakKataGames[message.from];
    return message.reply(`🏳️ Menyerah! Jawabannya adalah *${kata}*`);
}

// Cek jawaban tebak kata
if (global.tebakKataGames[message.from] && !lower.startsWith('.')) {
    const game = global.tebakKataGames[message.from];
    const jawaban = text.trim().toUpperCase();
    game.attempts++;

    if (jawaban === game.kata) {
        delete global.tebakKataGames[message.from];
        return message.reply(
`🎉 *BENAR!*
━━━━━━━━━━━━━━━
✅ Kata     : *${game.kata}*
🎯 Percobaan: *${game.attempts} kali*
💡 Hint dipakai: ${game.hintIdx + 1}/${game.hints.length}
━━━━━━━━━━━━━━━
Ketik _.tebakkata_ untuk main lagi!`
        );
    } else {
        // Kasih clue huruf yang bener
        let clue = '';
        for (let i = 0; i < game.kata.length; i++) {
            clue += game.kata[i] === jawaban[i] ? game.kata[i] : '_';
        }
        return message.reply(
`❌ Salah! (percobaan ke-${game.attempts})
🔤 Posisi benar: *${clue.split('').join(' ')}*
💡 Ketik _.hinttebak_ untuk hint berikutnya`
        );
    }
}


// ════════════════════════════════════════════════════════════
//  .trivia — Kuis trivia bahasa Indonesia
// ════════════════════════════════════════════════════════════
if (!global.triviaGames) global.triviaGames = {};

if (lower === '.trivia') {
    await message.reply('🧠 Membuat soal trivia...');

    try {
        const kategori = ['sejarah Indonesia', 'geografi Indonesia', 'budaya Indonesia', 'sains', 'olahraga', 'film & musik Indonesia', 'kuliner Indonesia'][Math.floor(Math.random() * 7)];

        const prompt = `Buatkan 1 soal trivia tentang ${kategori} dalam bahasa Indonesia.
Format WAJIB (JSON only):
{
  "soal": "pertanyaan disini",
  "pilihan": ["A. pilihan1", "B. pilihan2", "C. pilihan3", "D. pilihan4"],
  "jawaban": "A",
  "penjelasan": "penjelasan singkat kenapa jawabannya itu"
}`;

        const raw  = await tanyaAI('Kamu generator soal trivia bahasa Indonesia. Selalu jawab JSON valid saja, tanpa teks lain.', prompt, 300);
        const json = raw.replace(/```json|```/g, '').trim();
        const data = JSON.parse(json);

        global.triviaGames[message.from] = {
            jawaban:     data.jawaban.toUpperCase(),
            penjelasan:  data.penjelasan,
            soal:        data.soal,
            answered:    false
        };

        return message.reply(
`🧠 *TRIVIA — ${kategori.toUpperCase()}*
━━━━━━━━━━━━━━━
❓ ${data.soal}
━━━━━━━━━━━━━━━
${data.pilihan.join('\n')}
━━━━━━━━━━━━━━━
Ketik *A*, *B*, *C*, atau *D* untuk menjawab!`
        );

    } catch(e) {
        console.error('[TRIVIA]', e.message);
        return message.reply('❌ Gagal buat soal trivia, coba lagi');
    }
}

// Cek jawaban trivia
if (global.triviaGames[message.from] &&
    ['a','b','c','d'].includes(lower) &&
    !global.triviaGames[message.from].answered) {

    const game   = global.triviaGames[message.from];
    const jawaban = lower.toUpperCase();
    game.answered = true;

    if (jawaban === game.jawaban) {
        delete global.triviaGames[message.from];
        return message.reply(
`✅ *BENAR!* 🎉
━━━━━━━━━━━━━━━
📖 ${game.penjelasan}
━━━━━━━━━━━━━━━
Ketik _.trivia_ untuk soal berikutnya!`
        );
    } else {
        delete global.triviaGames[message.from];
        return message.reply(
`❌ *SALAH!*
━━━━━━━━━━━━━━━
✅ Jawaban benar: *${game.jawaban}*
📖 ${game.penjelasan}
━━━━━━━━━━━━━━━
Ketik _.trivia_ untuk coba lagi!`
        );
    }
}


// ════════════════════════════════════════════════════════════
//  .ship <nama1> <nama2> — Ship 2 orang
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.ship ')) {
    const parts = text.slice(6).trim().split(/\s+&\s+|\s+dan\s+|,\s*/i);
    let nama1, nama2;

    if (parts.length >= 2) {
        nama1 = parts[0].trim();
        nama2 = parts[1].trim();
    } else {
        const words = text.slice(6).trim().split(/\s+/);
        const mid   = Math.floor(words.length / 2);
        nama1 = words.slice(0, mid).join(' ');
        nama2 = words.slice(mid).join(' ');
    }

    if (!nama1 || !nama2) {
        return message.reply('Contoh: .ship Budi & Siti\nAtau: .ship Budi Siti');
    }

    // Generate persentase dari nama (konsisten untuk pasangan yang sama)
    const seed = [...(nama1 + nama2).toLowerCase()].reduce((a, c) => a + c.charCodeAt(0), 0);
    const pct  = (seed % 71) + 30; // 30-100%

    const bar   = '█'.repeat(Math.floor(pct / 10)) + '░'.repeat(10 - Math.floor(pct / 10));
    let status, emoji;

    if (pct >= 90)      { status = 'Jodoh banget! Nikah aja!';        emoji = '💍'; }
    else if (pct >= 75) { status = 'Sangat cocok! PDKT aja!';         emoji = '💕'; }
    else if (pct >= 60) { status = 'Lumayan cocok, ada peluang nih!'; emoji = '💓'; }
    else if (pct >= 45) { status = 'Perlu usaha lebih keras!';        emoji = '💛'; }
    else if (pct >= 30) { status = 'Kurang cocok, tapi siapa tau...'; emoji = '🤔'; }
    else                { status = 'Kayaknya beda jalan deh...';      emoji = '💔'; }

    // Buat nama ship (gabungan)
    const shipName = nama1.slice(0, Math.ceil(nama1.length/2)) + nama2.slice(Math.floor(nama2.length/2)).toLowerCase();

    return message.reply(
`${emoji} *SHIP METER* ${emoji}
━━━━━━━━━━━━━━━
💑 *${nama1}* & *${nama2}*
🏷️ Ship name: *${shipName}*
━━━━━━━━━━━━━━━
❤️ Kompatibilitas:
[${bar}] *${pct}%*
━━━━━━━━━━━━━━━
📊 ${status}
━━━━━━━━━━━━━━━
_Hasil murni ilmiah, tidak ada yang bisa membantah_ 😌`
    );
}


// ════════════════════════════════════════════════════════════
//  .berita — Berita terkini Indonesia
// ════════════════════════════════════════════════════════════
if (lower === '.berita' || lower.startsWith('.berita ')) {
    const topik = lower.startsWith('.berita ') ? text.slice(8).trim() : '';
    await message.reply('📰 Mengambil berita terkini...');

    try {
        const { execSync } = require('child_process');

        // RSS feed berita Indonesia
        const feeds = [
            'https://www.cnnindonesia.com/rss',
            'https://rss.tempo.co/',
            'https://www.tribunnews.com/rss',
        ];

        const feed    = feeds[Math.floor(Math.random() * feeds.length)];
        const rssData = execSync(
            `curl -s -m 10 -H "User-Agent: Mozilla/5.0" "${feed}"`,
            { maxBuffer: 5 * 1024 * 1024 }
        ).toString();

        // Parse RSS sederhana
        const items = [...rssData.matchAll(/<item>([\s\S]*?)<\/item>/g)].slice(0, 5);

        if (!items.length) throw new Error('Tidak ada berita');

        let reply = `📰 *Berita Terkini Indonesia*\n`;
        if (topik) reply += `🔍 Topik: *${topik}*\n`;
        reply += `━━━━━━━━━━━━━━━\n`;

        let count = 0;
        for (const item of items) {
            const titleMatch = item[1].match(/<title><!\[CDATA\[(.*?)\]\]><\/title>/) ||
                               item[1].match(/<title>(.*?)<\/title>/);
            const linkMatch  = item[1].match(/<link>(.*?)<\/link>/) ||
                               item[1].match(/<guid[^>]*>(.*?)<\/guid>/);

            if (!titleMatch) continue;

            const title = titleMatch[1]
                .replace(/<!\[CDATA\[|\]\]>/g, '')
                .replace(/&amp;/g, '&')
                .replace(/&lt;/g, '<')
                .replace(/&gt;/g, '>')
                .trim();

            // Filter topik kalau ada
            if (topik && !title.toLowerCase().includes(topik.toLowerCase())) continue;

            count++;
            reply += `*${count}.* ${title}\n`;
            if (linkMatch) reply += `🔗 ${linkMatch[1].replace(/<!\[CDATA\[|\]\]>/g, '').trim()}\n`;
            reply += `\n`;

            if (count >= 5) break;
        }

        if (count === 0) {
            reply += `Tidak ada berita tentang "${topik}"`;
        }

        reply += `━━━━━━━━━━━━━━━\n🕐 ${new Date().toLocaleString('id-ID')}`;
        return message.reply(reply.trim());

    } catch(e) {
        console.error('[BERITA]', e.message);
        return message.reply('❌ Gagal ambil berita, coba lagi');
    }
}


// ════════════════════════════════════════════════════════════
//  .cerita <tema> — Generate cerita pendek bahasa Indonesia
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.cerita ')) {
    const tema = text.slice(8).trim();
    if (!tema) return message.reply(
        'Contoh:\n' +
        '• _.cerita persahabatan di desa_\n' +
        '• _.cerita petualangan anak SMA_\n' +
        '• _.cerita horor rumah tua_\n' +
        '• _.cerita lucu pedagang bakso_'
    );

    await message.reply('✍️ Menulis cerita...');

    try {
        const cerita = await tanyaAI(
            'Kamu penulis cerita pendek Indonesia yang kreatif. Tulis cerita yang menarik, natural, dan mengalir. Bahasa Indonesia yang baik dan mudah dipahami.',
            `Tulis cerita pendek (200-300 kata) dengan tema: "${tema}". 
Cerita harus punya:
- Tokoh yang jelas
- Konflik menarik  
- Ending yang memuaskan
Tulis langsung ceritanya tanpa judul atau pengantar.`,
            600
        );

        return message.reply(
`✍️ *Cerita: ${tema}*
━━━━━━━━━━━━━━━
${cerita}
━━━━━━━━━━━━━━━
_Dibuat oleh AI ✨_`
        );

    } catch(e) {
        console.error('[CERITA]', e.message);
        return message.reply('❌ Gagal buat cerita, coba lagi');
    }
}


// ════════════════════════════════════════════════════════════
//  .puisi <tema> — Generate puisi bahasa Indonesia
// ════════════════════════════════════════════════════════════
if (lower.startsWith('.puisi ')) {
    const tema = text.slice(7).trim();
    if (!tema) return message.reply(
        'Contoh:\n' +
        '• _.puisi rindu_\n' +
        '• _.puisi hujan sore hari_\n' +
        '• _.puisi semangat belajar_\n' +
        '• _.puisi cinta pertama_'
    );

    await message.reply('🎭 Menulis puisi...');

    try {
        const jenis = ['pantun', 'puisi bebas', 'syair'][Math.floor(Math.random() * 3)];

        const puisi = await tanyaAI(
            'Kamu penyair Indonesia berbakat. Tulis puisi yang indah, penuh makna, dan menyentuh hati. Gunakan bahasa Indonesia yang puitis dan metafora yang kuat.',
            `Tulis ${jenis} dengan tema "${tema}".
${jenis === 'pantun' ? 'Pantun 4 baris: 2 baris sampiran, 2 baris isi. Buat 3-4 bait.' : ''}
${jenis === 'syair' ? 'Syair 4 baris dengan rima a-a-a-a. Buat 3-4 bait.' : ''}
${jenis === 'puisi bebas' ? 'Puisi bebas 10-16 baris, tidak harus berima tapi harus bermakna.' : ''}
Tulis langsung puisinya tanpa pengantar.`,
            400
        );

        return message.reply(
`🎭 *${jenis.charAt(0).toUpperCase() + jenis.slice(1)}: ${tema}*
━━━━━━━━━━━━━━━
${puisi}
━━━━━━━━━━━━━━━
_Dibuat oleh AI ✨_`
        );

    } catch(e) {
        console.error('[PUISI]', e.message);
        return message.reply('❌ Gagal buat puisi, coba lagi');
    }
}

// ════════════════════════════════════════════════════════════
//  .tebakkarakter — Tebak karakter anime dari gambar
// ════════════════════════════════════════════════════════════
if (!global.tebakAnimeGames) global.tebakAnimeGames = {};

if (lower === '.tebakkarakter') {
    await message.reply('🎮 Loading karakter random...');

    try {
        const { execSync } = require('child_process');

        // Random page biar bervariasi
        const page = Math.floor(Math.random() * 15) + 1;
        const url  = `https://api.jikan.moe/v4/characters?order_by=favorites&sort=desc&limit=25&page=${page}`;

        const raw  = execSync(
            `curl -s -m 15 -H "User-Agent: Mozilla/5.0" -H "Accept: application/json" "${url}"`,
            { maxBuffer: 5 * 1024 * 1024 }
        ).toString();

        const data = JSON.parse(raw);
        const list = data?.data?.filter(c =>
            c.images?.jpg?.image_url &&
            c.name &&
            c.favorites > 100  // hanya karakter yang lumayan terkenal
        );

        if (!list?.length) return message.reply('❌ Gagal ambil karakter, coba lagi');

        // Pilih random
        const char     = list[Math.floor(Math.random() * list.length)];
        const imgUrl   = char.images?.jpg?.image_url;
        const namaAsli = char.name;
        const anime    = char.anime?.[0]?.anime?.title ?? 'Unknown';

        // Buat hints dari data karakter
        const hints = [
            `Karakter dari anime: *${anime}*`,
            `Favorit oleh *${char.favorites?.toLocaleString('id-ID') ?? '?'}* orang di MAL`,
            `Nama terdiri dari *${namaAsli.split(' ').length}* kata, *${namaAsli.replace(/ /g,'').length}* huruf total`,
        ];

        // Simpan state game
        global.tebakAnimeGames[message.from] = {
            nama:     namaAsli,
            namaLow:  namaAsli.toLowerCase(),
            // Simpan juga nama yang dipecah (first name / last name)
            namaWords: namaAsli.toLowerCase().split(' '),
            anime:    anime,
            hints:    hints,
            hintIdx:  0,
            attempts: 0,
            imgUrl:   imgUrl
        };

        // Download dan kirim gambar
        const file = tmpFile('jpg');
        try {
            execSync(
                `curl -s -m 15 -L -o "${file}" "${imgUrl}"`,
                { maxBuffer: 10 * 1024 * 1024 }
            );

            if (!fs.existsSync(file) || fs.statSync(file).size < 500) {
                delete global.tebakAnimeGames[message.from];
                return message.reply('❌ Gagal download gambar karakter, coba lagi');
            }

            await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                caption:
`🎮 *TEBAK KARAKTER ANIME*
━━━━━━━━━━━━━━━
💡 Hint 1: ${hints[0]}
━━━━━━━━━━━━━━━
Siapa karakter ini? Ketik nama karakternya!
_.hinttebakkarakter_ → hint berikutnya
_.stoptebakkarakter_ → menyerah`
            });
        } finally {
            if (fs.existsSync(file)) fs.unlinkSync(file);
        }

    } catch(e) {
        console.error('[TEBAKKARAKTER]', e.message);
        return message.reply('❌ Gagal load karakter: ' + e.message.slice(0, 100));
    }
    return;
}

// ── Hint berikutnya ──────────────────────────────────────────
if (lower === '.hinttebakkarakter' && global.tebakAnimeGames[message.from]) {
    const game = global.tebakAnimeGames[message.from];
    game.hintIdx++;

    if (game.hintIdx >= game.hints.length) {
        // Hint terakhir — kasih huruf pertama nama
        const initials = game.namaWords.map(w => w[0].toUpperCase()).join(' - ');
        return message.reply(
`💡 *Hint Terakhir!*
Inisial nama: *${initials}*
━━━━━━━━━━━━━━━
Coba tebak atau ketik _.stoptebakkarakter_`
        );
    }

    return message.reply(`💡 *Hint ${game.hintIdx + 1}:* ${game.hints[game.hintIdx]}`);
}

// ── Menyerah ─────────────────────────────────────────────────
if (lower === '.stoptebakkarakter' && global.tebakAnimeGames[message.from]) {
    const game = global.tebakAnimeGames[message.from];
    const nama = game.nama;
    const anime = game.anime;

    // Kirim gambar lagi dengan jawaban
    try {
        const { execSync } = require('child_process');
        const file = tmpFile('jpg');
        try {
            execSync(
                `curl -s -m 15 -L -o "${file}" "${game.imgUrl}"`,
                { maxBuffer: 10 * 1024 * 1024 }
            );
            if (fs.existsSync(file) && fs.statSync(file).size > 500) {
                await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                    caption: `🏳️ *Menyerah!*\nJawabannya: *${nama}*\nDari anime: _${anime}_`
                });
                fs.unlinkSync(file);
                delete global.tebakAnimeGames[message.from];
                return;
            }
        } finally {
            if (fs.existsSync(file)) fs.unlinkSync(file);
        }
    } catch(_) {}

    delete global.tebakAnimeGames[message.from];
    return message.reply(`🏳️ Menyerah! Jawabannya: *${nama}*\nDari anime: _${anime}_`);
}

// ── Cek jawaban ───────────────────────────────────────────────
if (global.tebakAnimeGames[message.from] && !lower.startsWith('.')) {
    const game    = global.tebakAnimeGames[message.from];
    const tebakan = lower.trim();
    game.attempts++;

    // Cek apakah jawaban benar
    // Match kalau: nama lengkap, nama depan, nama belakang, atau sebagian nama
    const isBenar =
        tebakan === game.namaLow ||
        game.namaWords.includes(tebakan) ||
        game.namaLow.includes(tebakan) && tebakan.length >= 3;

    if (isBenar) {
        // Benar! Kirim gambar dengan jawaban
        try {
            const { execSync } = require('child_process');
            const file = tmpFile('jpg');
            try {
                execSync(
                    `curl -s -m 15 -L -o "${file}" "${game.imgUrl}"`,
                    { maxBuffer: 10 * 1024 * 1024 }
                );
                if (fs.existsSync(file) && fs.statSync(file).size > 500) {
                    await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                        caption:
`🎉 *BENAR!*
━━━━━━━━━━━━━━━
✅ Karakter  : *${game.nama}*
🎌 Anime    : _${game.anime}_
🎯 Percobaan: *${game.attempts} kali*
💡 Hint dipakai: ${game.hintIdx + 1}/${game.hints.length}
━━━━━━━━━━━━━━━
Ketik _.tebakkarakter_ untuk main lagi!`
                    });
                    fs.unlinkSync(file);
                    delete global.tebakAnimeGames[message.from];
                    return;
                }
            } finally {
                if (fs.existsSync(file)) fs.unlinkSync(file);
            }
        } catch(_) {}

        delete global.tebakAnimeGames[message.from];
        return message.reply(
`🎉 *BENAR!*
✅ *${game.nama}* dari _${game.anime}_
🎯 ${game.attempts} kali percobaan
Ketik _.tebakkarakter_ untuk main lagi!`
        );

    } else {
        // Salah
        const sisaHint = game.hints.length - game.hintIdx - 1;
        return message.reply(
`❌ Bukan *${text.trim()}*! (percobaan ke-${game.attempts})
${sisaHint > 0 ? `💡 Masih ada *${sisaHint}* hint tersisa — ketik _.hinttebakkarakter_` : '💡 Hint sudah habis! Ketik _.stoptebakkarakter_ kalau menyerah'}`
        );
    }
}

// ════════════════════════════════════════════════════
//  GENERATE AI IMAGE — Pollinations.ai
// ════════════════════════════════════════════════════
if (lower.startsWith('.imagine ')) {
    const prompt = text.slice(9).trim();
    if (!prompt) return message.reply('❌ Kasih prompt dulu!\nContoh: _.imagine anime girl with blue hair_');

    await message.reply('🎨 Generating image...');

    try {
        const encoded = encodeURIComponent(prompt);
        const imageUrl = `https://image.pollinations.ai/prompt/${encoded}?width=1024&height=1024&nologo=true&enhance=true`;

        const res = await axios.get(imageUrl, { 
            responseType: 'arraybuffer',
            timeout: 60000 // pollinations kadang lama
        });

        const file = tmpFile('jpg');
        try {
            fs.writeFileSync(file, res.data);
            await client.sendMessage(message.from, MessageMedia.fromFilePath(file), {
                caption: `🎨 *AI Generated Image*\n📝 Prompt: ${prompt}`
            });
        } finally {
            if (fs.existsSync(file)) fs.unlinkSync(file);
        }
    } catch (e) {
        console.error('[IMAGINE] Error:', e.message);
        await message.reply('❌ Gagal generate image, coba lagi nanti.');
    }
}

        // ════════════════════════════════════════════════════
        //  REMIND
        // ════════════════════════════════════════════════════
        if (lower.startsWith('.remind ')) {
            const parts  = text.split(' ');
            const durStr = parts[1];
            const pesan  = parts.slice(2).join(' ');
            if (!durStr || !pesan) return message.reply('Contoh: .remind 10m cek oven');
            const ms = parseDuration(durStr);
            if (!ms) return message.reply('Format: 30s / 10m / 2h');
            const chatId = message.from;
            await message.reply(`⏰ Oke, aku ingetin dalam *${durStr}*: _${pesan}_`);
            setTimeout(async () => {
                try { await client.sendMessage(chatId, `⏰ *REMINDER!*\n\n${pesan}`); }
                catch (e) { console.error('Reminder error:', e); }
            }, ms);
            return;
        }

    } catch (err) {
        console.error('[BOT ERROR]', err.message);
        message.reply(`❌ Error: ${err.message ?? 'Unknown error'}`);
    }
});

client.initialize();
