import { Router } from 'express';
import { db } from '../../core/db.js';
import { ensureDiscordImage, ensureDiscordEmoji } from '../../lib/image-convert.js';
import { userOwnsGuild, getOwnedGuildIds, getPaymentConfig, upsertPaymentConfig, getGuildConfig, updateGuildConfig } from '../../core/db.js';
import { encryptSecret, decryptSecret, maskSecret } from '../../lib/secure.js';

export const apiRouter = Router();

// Middleware: izinkan akses kalau (a) sudah login via session, ATAU (b) bawa dashboard token
apiRouter.use((req, res, next) => {
  if (req.user) return next(); // session login valid (di-set authMiddleware)
  const token = req.headers['x-dashboard-token'] || req.query.token;
  const expected = process.env.DASHBOARD_TOKEN;
  if (expected && token === expected) return next();
  return res.status(401).json({ error: 'unauthorized' });
});

// ---- Isolasi data per-user ----
// Boleh akses guild ini? legacy-token & admin = full; user biasa = hanya guild miliknya.
function canAccessGuild(req, guildId) {
  if (!req.user) return true;                 // legacy dashboard token
  if (req.user.role === 'admin') return true; // admin lihat semua
  if (!guildId) return false;
  return userOwnsGuild(req.user.id, String(guildId));
}

// Resolve guild_id pemilik sebuah resource (table harus punya kolom guild_id)
function resourceGuild(table, id) {
  const allowed = { store_panels: 1, categories: 1, products: 1 };
  if (!allowed[table]) return null;
  const row = db.prepare(`SELECT guild_id FROM ${table} WHERE id = ?`).get(id);
  return row?.guild_id || null;
}

// product_id -> guild_id
function productGuild(productId) {
  const row = db.prepare('SELECT guild_id FROM products WHERE id = ?').get(productId);
  return row?.guild_id || null;
}

// stock_id -> guild_id (via product)
function stockGuild(stockId) {
  const row = db.prepare(`
    SELECT p.guild_id AS guild_id FROM stock s
    JOIN products p ON p.id = s.product_id WHERE s.id = ?
  `).get(stockId);
  return row?.guild_id || null;
}

// Guard helper: kirim 403 kalau gak boleh. Return true kalau lolos.
function ensureGuild(req, res, guildId) {
  if (canAccessGuild(req, guildId)) return true;
  res.status(403).json({ error: 'forbidden: bukan guild kamu' });
  return false;
}

// ===== Guild list =====
apiRouter.get('/guilds', (req, res) => {
  // User biasa: hanya guild miliknya. Admin / legacy-token: semua.
  if (req.user && req.user.role !== 'admin') {
    const owned = getOwnedGuildIds(req.user.id);
    if (!owned.length) return res.json([]);
    const placeholders = owned.map(() => '?').join(',');
    const rows = db.prepare(
      `SELECT guild_id, name FROM guilds WHERE guild_id IN (${placeholders}) ORDER BY created_at DESC`
    ).all(...owned);
    return res.json(rows);
  }
  const rows = db.prepare('SELECT guild_id, name FROM guilds ORDER BY created_at DESC').all();
  res.json(rows);
});

// ===== Panels =====
apiRouter.get('/panels', (req, res) => {
  const guildId = req.query.guild_id;
  if (!ensureGuild(req, res, guildId)) return;
  const rows = db.prepare(`
    SELECT p.*, (SELECT COUNT(*) FROM categories WHERE panel_id = p.id) AS category_count
    FROM store_panels p WHERE guild_id = ? ORDER BY id DESC
  `).all(guildId);
  res.json(rows);
});

apiRouter.post('/panels', (req, res) => {
  const { guild_id, title, image_url, footer_note, placeholder, copyright } = req.body;
  if (!guild_id || !title) return res.status(400).json({ error: 'guild_id and title required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const r = db.prepare(`
    INSERT INTO store_panels (guild_id, title, image_url, footer_note, placeholder, copyright)
    VALUES (?, ?, ?, ?, ?, ?)
  `).run(guild_id, title, image_url || null, footer_note || null, placeholder || 'Pilih Di Sini', copyright || null);
  res.json({ id: r.lastInsertRowid });
});

apiRouter.put('/panels/:id', (req, res) => {
  if (!ensureGuild(req, res, resourceGuild('store_panels', req.params.id))) return;
  const { title, image_url, footer_note, placeholder, copyright, enabled } = req.body;
  db.prepare(`
    UPDATE store_panels SET
      title = COALESCE(?, title),
      image_url = COALESCE(?, image_url),
      footer_note = COALESCE(?, footer_note),
      placeholder = COALESCE(?, placeholder),
      copyright = COALESCE(?, copyright),
      enabled = COALESCE(?, enabled)
    WHERE id = ?
  `).run(title, image_url, footer_note, placeholder, copyright, enabled, req.params.id);
  res.json({ ok: true });
});

apiRouter.delete('/panels/:id', (req, res) => {
  if (!ensureGuild(req, res, resourceGuild('store_panels', req.params.id))) return;
  db.prepare('DELETE FROM store_panels WHERE id = ?').run(req.params.id);
  res.json({ ok: true });
});

// ===== Categories =====
apiRouter.get('/categories', (req, res) => {
  const { guild_id, panel_id } = req.query;
  if (!ensureGuild(req, res, guild_id)) return;
  let query = `SELECT c.*, (SELECT COUNT(*) FROM products WHERE category_id = c.id) AS product_count FROM categories c WHERE guild_id = ?`;
  const params = [guild_id];
  if (panel_id) { query += ' AND panel_id = ?'; params.push(panel_id); }
  query += ' ORDER BY sort_order, id';
  res.json(db.prepare(query).all(...params));
});

apiRouter.post('/categories', (req, res) => {
  const { guild_id, panel_id, name, emoji, description, note, sort_order } = req.body;
  if (!guild_id || !name) return res.status(400).json({ error: 'guild_id and name required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const r = db.prepare(`
    INSERT INTO categories (guild_id, panel_id, name, emoji, description, note, sort_order)
    VALUES (?, ?, ?, ?, ?, ?, ?)
  `).run(guild_id, panel_id || null, name, emoji || null, description || null, note || null, sort_order || 0);
  res.json({ id: r.lastInsertRowid });
});

apiRouter.put('/categories/:id', (req, res) => {
  if (!ensureGuild(req, res, resourceGuild('categories', req.params.id))) return;
  const { name, emoji, description, note, sort_order, enabled, panel_id } = req.body;
  db.prepare(`
    UPDATE categories SET
      name = COALESCE(?, name),
      emoji = COALESCE(?, emoji),
      description = COALESCE(?, description),
      note = COALESCE(?, note),
      sort_order = COALESCE(?, sort_order),
      enabled = COALESCE(?, enabled),
      panel_id = COALESCE(?, panel_id)
    WHERE id = ?
  `).run(name, emoji, description, note, sort_order, enabled, panel_id, req.params.id);
  res.json({ ok: true });
});

apiRouter.delete('/categories/:id', (req, res) => {
  if (!ensureGuild(req, res, resourceGuild('categories', req.params.id))) return;
  db.prepare('DELETE FROM categories WHERE id = ?').run(req.params.id);
  res.json({ ok: true });
});

// ===== Products =====
apiRouter.get('/products', (req, res) => {
  const { guild_id, category_id } = req.query;
  if (!ensureGuild(req, res, guild_id)) return;
  let query = `
    SELECT p.*,
      c.name AS category_name, c.emoji AS category_emoji,
      (SELECT COUNT(*) FROM stock WHERE product_id = p.id AND sold = 0) AS stock_available,
      (SELECT COUNT(*) FROM stock WHERE product_id = p.id AND sold = 1) AS stock_sold
    FROM products p
    LEFT JOIN categories c ON c.id = p.category_id
    WHERE p.guild_id = ?
  `;
  const params = [guild_id];
  if (category_id) { query += ' AND category_id = ?'; params.push(category_id); }
  query += ' ORDER BY p.sort_order, p.id';
  res.json(db.prepare(query).all(...params));
});

apiRouter.post('/products', (req, res) => {
  const { guild_id, category_id, name, description, price, price_max, image_url, auto_delivery, sort_order, sku } = req.body;
  if (!guild_id || !name || !price) return res.status(400).json({ error: 'guild_id, name, price required' });
  if (!ensureGuild(req, res, guild_id)) return;

  // Validate SKU uniqueness if provided
  if (sku) {
    const existing = db.prepare('SELECT id FROM products WHERE sku = ?').get(sku);
    if (existing) return res.status(400).json({ error: `SKU "${sku}" already exists` });
  }

  const r = db.prepare(`
    INSERT INTO products (guild_id, category_id, name, description, price, price_max, image_url, auto_delivery, sort_order, sku)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  `).run(guild_id, category_id || null, name, description || null, price, price_max || null, image_url || null, auto_delivery !== false ? 1 : 0, sort_order || 0, sku || null);
  res.json({ id: r.lastInsertRowid });
});

apiRouter.put('/products/:id', (req, res) => {
  if (!ensureGuild(req, res, productGuild(req.params.id))) return;
  const f = req.body;

  // Validate SKU uniqueness if provided
  if (f.sku) {
    const existing = db.prepare('SELECT id FROM products WHERE sku = ? AND id != ?').get(f.sku, req.params.id);
    if (existing) return res.status(400).json({ error: `SKU "${f.sku}" already exists` });
  }

  db.prepare(`
    UPDATE products SET
      sku = COALESCE(?, sku),
      name = COALESCE(?, name),
      description = COALESCE(?, description),
      price = COALESCE(?, price),
      price_max = COALESCE(?, price_max),
      category_id = COALESCE(?, category_id),
      image_url = COALESCE(?, image_url),
      auto_delivery = COALESCE(?, auto_delivery),
      sort_order = COALESCE(?, sort_order),
      enabled = COALESCE(?, enabled)
    WHERE id = ?
  `).run(
    f.sku, f.name, f.description, f.price, f.price_max, f.category_id, f.image_url,
    f.auto_delivery, f.sort_order, f.enabled, req.params.id
  );
  res.json({ ok: true });
});

apiRouter.delete('/products/:id', (req, res) => {
  if (!ensureGuild(req, res, productGuild(req.params.id))) return;
  db.prepare('DELETE FROM products WHERE id = ?').run(req.params.id);
  res.json({ ok: true });
});

// ===== Stock =====
apiRouter.get('/stock', (req, res) => {
  const { product_id } = req.query;
  if (!ensureGuild(req, res, productGuild(product_id))) return;
  res.json(db.prepare(`
    SELECT id, product_id, content, sold, sold_at FROM stock
    WHERE product_id = ? ORDER BY sold, id DESC
  `).all(product_id));
});

apiRouter.post('/stock', (req, res) => {
  const { product_id, content } = req.body;
  if (!product_id || !content) return res.status(400).json({ error: 'product_id and content required' });
  if (!ensureGuild(req, res, productGuild(product_id))) return;
  const items = String(content).split('\n').map(s => s.trim()).filter(Boolean);
  const stmt = db.prepare('INSERT INTO stock (product_id, content) VALUES (?, ?)');
  const tx = db.transaction((items) => items.forEach(i => stmt.run(product_id, i)));
  tx(items);
  res.json({ added: items.length });
});

apiRouter.delete('/stock/:id', (req, res) => {
  if (!ensureGuild(req, res, stockGuild(req.params.id))) return;
  db.prepare('DELETE FROM stock WHERE id = ? AND sold = 0').run(req.params.id);
  res.json({ ok: true });
});

// ===== Stats =====
apiRouter.get('/stats', (req, res) => {
  const { guild_id } = req.query;

  // User biasa tanpa guild_id tidak boleh lihat statistik global
  if (!guild_id && req.user && req.user.role !== 'admin') {
    return res.status(400).json({ error: 'guild_id required' });
  }

  if (guild_id) {
    if (!ensureGuild(req, res, guild_id)) return;
    const stats = db.prepare(`
      SELECT
        (SELECT COUNT(*) FROM orders WHERE guild_id = ? AND status = 'delivered') AS orders_delivered,
        (SELECT IFNULL(SUM(total), 0) FROM orders WHERE guild_id = ? AND status = 'delivered') AS revenue,
        (SELECT COUNT(*) FROM orders WHERE guild_id = ? AND status = 'pending') AS orders_pending,
        (SELECT COUNT(*) FROM tickets WHERE guild_id = ? AND status = 'open') AS tickets_open,
        (SELECT COUNT(*) FROM products WHERE guild_id = ? AND enabled = 1) AS products_active
    `).get(guild_id, guild_id, guild_id, guild_id, guild_id);
    return res.json(stats);
  }

  // Global stats (admin / legacy-token only)
  const stats = db.prepare(`
    SELECT
      (SELECT COUNT(*) FROM orders WHERE status = 'delivered') AS orders_delivered,
      (SELECT IFNULL(SUM(total), 0) FROM orders WHERE status = 'delivered') AS revenue,
      (SELECT COUNT(*) FROM orders WHERE status = 'pending') AS orders_pending,
      (SELECT COUNT(*) FROM tickets WHERE status = 'open') AS tickets_open,
      (SELECT COUNT(*) FROM products WHERE enabled = 1) AS products_active
  `).get();
  res.json(stats);
});

// ===== Recent orders =====
apiRouter.get('/orders', (req, res) => {
  const { guild_id } = req.query;
  // User biasa wajib pakai guild_id (gak boleh lihat semua order global)
  if (!guild_id && req.user && req.user.role !== 'admin') {
    return res.status(400).json({ error: 'guild_id required' });
  }
  if (guild_id && !ensureGuild(req, res, guild_id)) return;
  const filter = guild_id ? 'WHERE o.guild_id = ?' : '';
  const params = guild_id ? [guild_id] : [];
  res.json(db.prepare(`
    SELECT o.*, p.name AS product_name FROM orders o
    LEFT JOIN products p ON p.id = o.product_id
    ${filter}
    ORDER BY o.created_at DESC LIMIT 50
  `).all(...params));
});

// ===== Revenue series (buat grafik di #dashboard) =====
apiRouter.get('/revenue-series', (req, res) => {
  const { guild_id } = req.query;
  if (!guild_id && req.user && req.user.role !== 'admin') {
    return res.status(400).json({ error: 'guild_id required' });
  }
  if (guild_id && !ensureGuild(req, res, guild_id)) return;

  // days: 7..90, default 30
  let days = parseInt(req.query.days, 10);
  if (!Number.isFinite(days) || days < 7) days = 30;
  if (days > 90) days = 90;

  const now = Math.floor(Date.now() / 1000);
  const since = now - days * 86400;

  // Agregasi revenue + jumlah order per hari (UTC) dari order delivered
  const where = guild_id ? 'guild_id = ? AND' : '';
  const params = guild_id ? [guild_id, since] : [since];
  const rows = db.prepare(`
    SELECT
      CAST((COALESCE(paid_at, created_at)) / 86400 AS INTEGER) AS day_idx,
      IFNULL(SUM(total), 0) AS revenue,
      COUNT(*) AS orders
    FROM orders
    WHERE ${where} status = 'delivered' AND COALESCE(paid_at, created_at) >= ?
    GROUP BY day_idx
  `).all(...params);

  // Map day_idx -> data, lalu isi seri penuh (hari kosong = 0)
  const byDay = new Map(rows.map(r => [r.day_idx, r]));
  const series = [];
  const startIdx = Math.floor(since / 86400);
  const endIdx = Math.floor(now / 86400);
  for (let d = startIdx; d <= endIdx; d++) {
    const hit = byDay.get(d);
    series.push({
      date: new Date(d * 86400 * 1000).toISOString().slice(0, 10),
      revenue: hit ? hit.revenue : 0,
      orders: hit ? hit.orders : 0,
    });
  }
  const totalRevenue = series.reduce((s, x) => s + x.revenue, 0);
  const totalOrders = series.reduce((s, x) => s + x.orders, 0);
  res.json({ days, series, totalRevenue, totalOrders });
});

// ===== Send panel to Discord =====
apiRouter.post('/panels/:id/send', async (req, res) => {
  const { channel_id } = req.body;
  if (!channel_id) return res.status(400).json({ error: 'channel_id required' });
  if (!ensureGuild(req, res, resourceGuild('store_panels', req.params.id))) return;
  const client = req.app.get('discord-client');
  try {
    const { sendStorePanel } = await import('../../modules/store/render.js');
    const result = await sendStorePanel(client, parseInt(req.params.id), channel_id);
    res.json(result);
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ===== Channels (for picker) =====
apiRouter.get('/channels', async (req, res) => {
  const { guild_id } = req.query;
  if (!guild_id) return res.status(400).json({ error: 'guild_id required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const guild = await client.guilds.fetch(guild_id);
    await guild.channels.fetch();
    // Group: categories + text channels under them
    const channels = [...guild.channels.cache.values()]
      .filter(c => c.type === 0 || c.type === 4 || c.type === 5) // text + category + announcement
      .sort((a, b) => {
        if (a.parentId === b.parentId) return a.rawPosition - b.rawPosition;
        return (a.parent?.rawPosition || 0) - (b.parent?.rawPosition || 0);
      })
      .map(c => ({
        id: c.id,
        name: c.name,
        type: c.type,
        parent_id: c.parentId,
        parent_name: c.parent?.name || null,
      }));
    res.json(channels);
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ===== Send ticket panel (order panel) =====
apiRouter.post('/ticket-panel/send', async (req, res) => {
  const { guild_id, channel_id, title, rules, placeholder, color, mention_everyone } = req.body;
  if (!channel_id) return res.status(400).json({ error: 'channel_id required' });
  if (!ensureGuild(req, res, guild_id)) return;

  const client = req.app.get('discord-client');
  try {
    const { ActionRowBuilder, StringSelectMenuBuilder, EmbedBuilder } = await import('discord.js');

    const products = db.prepare(`
      SELECT p.*, c.name AS category_name, c.emoji AS category_emoji,
        (SELECT COUNT(*) FROM stock WHERE product_id = p.id AND sold = 0) AS stock_count
      FROM products p
      LEFT JOIN categories c ON c.id = p.category_id
      WHERE p.guild_id = ? AND p.enabled = 1
      ORDER BY c.sort_order, p.sort_order, p.id
    `).all(guild_id);

    if (!products.length) {
      return res.status(400).json({ error: 'Belum ada produk. Tambah produk di dashboard dulu.' });
    }

    const channel = await client.channels.fetch(channel_id);
    const cfg = getGuildConfig(guild_id);

    const rulesLines = (rules || '').split('\n').filter(l => l.trim());
    const rulesText = rulesLines.length
      ? '**Notes:**\n' + rulesLines.map(l => `${l.trim()}`).join('\n')
      : '';

    const embedColor = color ? parseInt(color.replace('#', ''), 16) : (cfg.ticket_color ? parseInt(cfg.ticket_color.replace('#', ''), 16) : 0x5865f2);

    const embed = new EmbedBuilder()
      .setTitle(title || '🛒 ORDER PRODUK')
      .setColor(embedColor)
      .setDescription([
        'Pilih Sesuai Kategori Yang Kamu Mau',
        '',
        rulesText,
      ].filter(Boolean).join('\n'))
      .setFooter({ text: 'Pilih produk → lihat detail → klik ORDER' });

    const emojiStock = cfg.emoji_stock || '📦';

    const select = new StringSelectMenuBuilder()
      .setCustomId('order_select_product')
      .setPlaceholder(placeholder || 'Pilih Di Sini')
      .addOptions(products.slice(0, 25).map(p => {
        const catLabel = p.category_name ? `${p.category_emoji || ''} ${p.category_name}` : 'Produk';
        const opt = {
          label: p.name.slice(0, 100),
          value: `${p.id}`,
          description: `${catLabel} — Rp${p.price.toLocaleString('id-ID')} | Stock: ${p.stock_count}`.slice(0, 100),
        };
        const customMatch = emojiStock.match(/<a?:(\w+):(\d+)>/);
        if (customMatch) opt.emoji = { id: customMatch[2], name: customMatch[1], animated: emojiStock.startsWith('<a:') };
        else opt.emoji = { name: emojiStock };
        return opt;
      }));

    const content = mention_everyone ? '@everyone' : '';
    const msg = await channel.send({
      content,
      embeds: [embed],
      components: [new ActionRowBuilder().addComponents(select)],
    });

    res.json({ ok: true, message_id: msg.id });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ===== Server Management (buat kategori + channel Discord) =====
apiRouter.post('/server/create-category', async (req, res) => {
  const { guild_id, name, private: isPrivate } = req.body;
  if (!guild_id || !name) return res.status(400).json({ error: 'guild_id and name required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const { ChannelType, PermissionFlagsBits } = await import('discord.js');
    const guild = await client.guilds.fetch(guild_id);
    const opts = { name, type: ChannelType.GuildCategory };
    if (isPrivate) {
      opts.permissionOverwrites = [{ id: guild.roles.everyone.id, deny: [PermissionFlagsBits.ViewChannel] }];
    }
    const cat = await guild.channels.create(opts);
    res.json({ id: cat.id, name: cat.name });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

apiRouter.post('/server/create-channel', async (req, res) => {
  const { guild_id, name, type, category_id, topic } = req.body;
  if (!guild_id || !name) return res.status(400).json({ error: 'guild_id and name required' });
  if (!ensureGuild(req, res, guild_id)) return;
  // type: 0=text, 2=voice, 5=announcement
  const allowedTypes = [0, 2, 5];
  const chType = allowedTypes.includes(Number(type)) ? Number(type) : 0;
  const client = req.app.get('discord-client');
  try {
    const guild = await client.guilds.fetch(guild_id);
    const opts = { name, type: chType };
    if (category_id) opts.parent = category_id;
    if (topic && chType !== 2) opts.topic = String(topic).slice(0, 1024);
    const ch = await guild.channels.create(opts);
    res.json({ id: ch.id, name: ch.name, type: ch.type });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

apiRouter.post('/server/deploy-template', async (req, res) => {
  const { guild_id, template } = req.body;
  if (!guild_id || !Array.isArray(template)) return res.status(400).json({ error: 'guild_id and template required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const { ChannelType, PermissionFlagsBits } = await import('discord.js');
    const guild = await client.guilds.fetch(guild_id);

    // Phase 1: Create roles
    const roleDefs = [
      { name: '👑 Owner', color: 0xF1C40F, hoist: true, permissions: [PermissionFlagsBits.Administrator] },
      { name: '🛡️ Admin', color: 0xE74C3C, hoist: true, permissions: [
        PermissionFlagsBits.ManageChannels, PermissionFlagsBits.ManageRoles,
        PermissionFlagsBits.ManageMessages, PermissionFlagsBits.KickMembers,
        PermissionFlagsBits.BanMembers, PermissionFlagsBits.ManageThreads,
        PermissionFlagsBits.ModerateMembers, PermissionFlagsBits.ViewAuditLog,
        PermissionFlagsBits.ManageNicknames, PermissionFlagsBits.ManageWebhooks,
        PermissionFlagsBits.MentionEveryone, PermissionFlagsBits.ManageGuildExpressions,
        PermissionFlagsBits.BypassSlowmode, PermissionFlagsBits.PinMessages,
      ]},
      { name: '⚔️ Staff', color: 0x3498DB, hoist: true, permissions: [
        PermissionFlagsBits.ManageMessages, PermissionFlagsBits.ManageThreads,
        PermissionFlagsBits.ModerateMembers, PermissionFlagsBits.KickMembers,
        PermissionFlagsBits.MentionEveryone, PermissionFlagsBits.BypassSlowmode,
        PermissionFlagsBits.PinMessages, PermissionFlagsBits.ViewAuditLog,
      ]},
      { name: '💰 Seller', color: 0x2ECC71, hoist: true, permissions: [
        PermissionFlagsBits.ManageMessages, PermissionFlagsBits.AttachFiles,
        PermissionFlagsBits.EmbedLinks, PermissionFlagsBits.ManageThreads,
        PermissionFlagsBits.BypassSlowmode, PermissionFlagsBits.PinMessages,
      ]},
      { name: '⭐ VIP', color: 0x9B59B6, hoist: true, permissions: [
        PermissionFlagsBits.AttachFiles, PermissionFlagsBits.EmbedLinks,
        PermissionFlagsBits.UseExternalEmojis, PermissionFlagsBits.AddReactions,
      ]},
      { name: '🛒 Buyer', color: 0x1ABC9C, hoist: false, permissions: [
        PermissionFlagsBits.SendMessages, PermissionFlagsBits.AddReactions,
        PermissionFlagsBits.ReadMessageHistory, PermissionFlagsBits.ViewChannel,
        PermissionFlagsBits.UseApplicationCommands,
      ]},
    ];

    const rolesCreated = [];
    const roleMap = {};
    for (const def of roleDefs) {
      let role = guild.roles.cache.find(r => r.name === def.name);
      if (!role) {
        role = await guild.roles.create({
          name: def.name, color: def.color, hoist: def.hoist,
          permissions: def.permissions, reason: 'HaikzBot template deploy',
        });
        rolesCreated.push(def.name);
      }
      roleMap[def.name] = role;
    }

    const staffRoleNames = ['👑 Owner', '🛡️ Admin', '⚔️ Staff'];
    const staffRoles = staffRoleNames.map(n => roleMap[n]).filter(Boolean);

    // Phase 2: Deploy channels with permission overwrites
    let cats = 0, channels = 0;
    const errors = [];

    for (const section of template) {
      let catId = null;
      const catOverwrites = [];

      // Category-level permission overwrites
      if (section.private || section.staffOnly) {
        catOverwrites.push({ id: guild.roles.everyone.id, deny: [PermissionFlagsBits.ViewChannel] });
        for (const sr of staffRoles) {
          catOverwrites.push({ id: sr.id, allow: [PermissionFlagsBits.ViewChannel] });
        }
        // Seller can see order/garansi ticket channels but not staff-only
        if (!section.staffOnly && roleMap['💰 Seller']) {
          catOverwrites.push({ id: roleMap['💰 Seller'].id, allow: [PermissionFlagsBits.ViewChannel] });
        }
      }

      try {
        const catOpts = { name: section.cat, type: ChannelType.GuildCategory };
        if (catOverwrites.length) catOpts.permissionOverwrites = catOverwrites;
        const cat = await guild.channels.create(catOpts);
        catId = cat.id;
        cats++;
      } catch (e) { errors.push(`cat "${section.cat}": ${e.message}`); continue; }

      for (const ch of (section.channels || [])) {
        try {
          const chOpts = { name: ch.name, type: ch.type ?? 0, parent: catId };
          // Per-channel overrides
          if (ch.overwrites) {
            const ow = [];
            if (ch.overwrites.denyEveryone) {
              ow.push({ id: guild.roles.everyone.id, deny: [PermissionFlagsBits.ViewChannel] });
            }
            if (ch.overwrites.readOnly) {
              ow.push({ id: guild.roles.everyone.id, deny: [PermissionFlagsBits.SendMessages] });
            }
            if (ch.overwrites.allowRoles) {
              for (const rn of ch.overwrites.allowRoles) {
                if (roleMap[rn]) ow.push({ id: roleMap[rn].id, allow: [PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages] });
              }
            }
            if (ow.length) chOpts.permissionOverwrites = ow;
          }
          if (ch.topic && ch.type !== 2) chOpts.topic = ch.topic;
          await guild.channels.create(chOpts);
          channels++;
        } catch (e) { errors.push(`ch "${ch.name}": ${e.message}`); }
      }
    }

    // Phase 3: Auto-configure ticket system
    const configUpdates = {};
    const allCats = await guild.channels.fetch();
    const orderCat = allCats.find(c => c.type === ChannelType.GuildCategory && /ticket.*order|order.*ticket/i.test(c.name));
    if (orderCat) configUpdates.ticket_category_id = orderCat.id;

    // Create ticket-logs channel in staff category
    const staffCat = allCats.find(c => c.type === ChannelType.GuildCategory && /staff/i.test(c.name));
    if (staffCat) {
      try {
        const logCh = await guild.channels.create({ name: '╭・📝\u200B┃\u200B𝘁𝗶𝗰𝗸𝗲𝘁-𝗹𝗼𝗴𝘀', type: ChannelType.GuildText, parent: staffCat.id,
          permissionOverwrites: [
            { id: guild.roles.everyone.id, deny: [PermissionFlagsBits.ViewChannel] },
            ...staffRoles.map(r => ({ id: r.id, allow: [PermissionFlagsBits.ViewChannel] })),
          ],
        });
        configUpdates.log_channel_id = logCh.id;
      } catch (e) { errors.push(`ticket-logs: ${e.message}`); }
    }

    // Set staff role in config
    if (roleMap['⚔️ Staff']) configUpdates.staff_role_id = roleMap['⚔️ Staff'].id;

    if (Object.keys(configUpdates).length) {
      updateGuildConfig(guild_id, configUpdates);
    }

    res.json({ ok: true, categories: cats, channels, roles_created: rolesCreated, config_set: configUpdates, errors });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

// ===== Create roles with permissions =====
apiRouter.post('/server/create-roles', async (req, res) => {
  const { guild_id } = req.body;
  if (!guild_id) return res.status(400).json({ error: 'guild_id required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const { PermissionsBitField } = await import('discord.js');
    const guild = await client.guilds.fetch(guild_id);
    const existing = guild.roles.cache;
    const created = [];
    const skipped = [];

    const roleDefs = [
      {
        name: '👑 Owner', color: 0xF1C40F, position: 10, hoist: true,
        permissions: [PermissionsBitField.Flags.Administrator],
      },
      {
        name: '🛡️ Admin', color: 0xE74C3C, position: 9, hoist: true,
        permissions: [
          PermissionsBitField.Flags.ManageChannels,
          PermissionsBitField.Flags.ManageRoles,
          PermissionsBitField.Flags.ManageMessages,
          PermissionsBitField.Flags.KickMembers,
          PermissionsBitField.Flags.BanMembers,
          PermissionsBitField.Flags.ManageThreads,
          PermissionsBitField.Flags.ModerateMembers,
          PermissionsBitField.Flags.ViewAuditLog,
          PermissionsBitField.Flags.ManageNicknames,
          PermissionsBitField.Flags.ManageWebhooks,
          PermissionsBitField.Flags.MentionEveryone,
          PermissionsBitField.Flags.ManageGuildExpressions,
          PermissionsBitField.Flags.BypassSlowmode,
          PermissionsBitField.Flags.PinMessages,
        ],
      },
      {
        name: '⚔️ Staff', color: 0x3498DB, position: 8, hoist: true,
        permissions: [
          PermissionsBitField.Flags.ManageMessages,
          PermissionsBitField.Flags.ManageThreads,
          PermissionsBitField.Flags.ModerateMembers,
          PermissionsBitField.Flags.KickMembers,
          PermissionsBitField.Flags.MentionEveryone,
          PermissionsBitField.Flags.BypassSlowmode,
          PermissionsBitField.Flags.PinMessages,
          PermissionsBitField.Flags.ViewAuditLog,
        ],
      },
      {
        name: '💰 Seller', color: 0x2ECC71, position: 7, hoist: true,
        permissions: [
          PermissionsBitField.Flags.ManageMessages,
          PermissionsBitField.Flags.AttachFiles,
          PermissionsBitField.Flags.EmbedLinks,
          PermissionsBitField.Flags.ManageThreads,
          PermissionsBitField.Flags.BypassSlowmode,
          PermissionsBitField.Flags.PinMessages,
        ],
      },
      {
        name: '⭐ VIP', color: 0x9B59B6, position: 6, hoist: true,
        permissions: [
          PermissionsBitField.Flags.AttachFiles,
          PermissionsBitField.Flags.EmbedLinks,
          PermissionsBitField.Flags.UseExternalEmojis,
          PermissionsBitField.Flags.AddReactions,
        ],
      },
      {
        name: '🛒 Buyer', color: 0x1ABC9C, position: 5, hoist: false,
        permissions: [
          PermissionsBitField.Flags.SendMessages,
          PermissionsBitField.Flags.AddReactions,
          PermissionsBitField.Flags.ReadMessageHistory,
          PermissionsBitField.Flags.ViewChannel,
          PermissionsBitField.Flags.UseApplicationCommands,
        ],
      },
    ];

    for (const def of roleDefs) {
      const found = existing.find(r => r.name === def.name);
      if (found) {
        skipped.push(def.name);
        continue;
      }
      try {
        await guild.roles.create({
          name: def.name,
          color: def.color,
          hoist: def.hoist,
          permissions: def.permissions,
          reason: 'HaikzBot template deploy',
        });
        created.push(def.name);
      } catch (e) { /* ignore individual role errors */ }
    }

    res.json({ ok: true, created, skipped });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

// ===== Delete all channels (for clean redeploy) =====
apiRouter.post('/server/delete-all-channels', async (req, res) => {
  const { guild_id } = req.body;
  if (!guild_id) return res.status(400).json({ error: 'guild_id required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const guild = await client.guilds.fetch(guild_id, { force: true });
    const channels = await guild.channels.fetch();
    let deleted = 0;
    const errors = [];

    // Delete non-category channels first, then categories
    const sorted = [...channels.values()].sort((a, b) => {
      if (a.type === 4 && b.type !== 4) return 1;
      if (a.type !== 4 && b.type === 4) return -1;
      return 0;
    });

    for (const ch of sorted) {
      try {
        await ch.delete('HaikzBot: clean redeploy');
        deleted++;
      } catch (e) { errors.push(ch.name); }
    }

    res.json({ ok: true, deleted, errors });
  } catch (e) { res.status(500).json({ error: e.message }); }
});

// ===== Send announcement =====
apiRouter.post('/announcement/send', async (req, res) => {
  const { channel_id, message, title, color, image_url, mention_everyone } = req.body;
  if (!channel_id || !message) return res.status(400).json({ error: 'channel_id and message required' });
  if (message.length > 4000) return res.status(400).json({ error: 'message too long (max 4000)' });

  const client = req.app.get('discord-client');
  try {
    const { EmbedBuilder } = await import('discord.js');
    const channel = await client.channels.fetch(channel_id);
    // Guard: channel harus di guild milik user
    if (!ensureGuild(req, res, channel?.guildId)) return;

    const colors = { red: 0xef4444, green: 0x10b981, blue: 0x5865f2, yellow: 0xfbbf24, purple: 0xa855f7 };
    const embedColor = colors[color] || colors.blue;

    const embed = new EmbedBuilder()
      .setColor(embedColor)
      .setDescription(message)
      .setTimestamp();

    if (title) embed.setTitle(title);
    if (image_url) embed.setImage(image_url);

    const content = mention_everyone ? '@everyone' : '';
    const msg = await channel.send({ content, embeds: [embed] });

    res.json({ ok: true, message_id: msg.id, url: msg.url });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ===== Upload Image (convert to Discord CDN URL) =====
apiRouter.post('/upload-image', async (req, res) => {
  const { guild_id, image_data, filename } = req.body;
  if (!guild_id || !image_data) return res.status(400).json({ error: 'guild_id and image_data required' });
  if (!ensureGuild(req, res, guild_id)) return;

  const client = req.app.get('discord-client');
  try {
    // image_data is base64 data URL: "data:image/png;base64,..."
    const matches = image_data.match(/^data:image\/(\w+);base64,(.+)$/);
    if (!matches) return res.status(400).json({ error: 'Invalid image data format' });

    const [, ext, base64] = matches;
    let buffer = Buffer.from(base64, 'base64');

    // Validate size (Discord max 256KB for emoji, 10MB upload limit — auto-compressed)
    if (buffer.length > 10 * 1024 * 1024) {
      return res.status(400).json({ error: 'Image too large (max 10MB)' });
    }

    const guild = await client.guilds.fetch(guild_id);

    // Discord emoji hanya terima PNG/JPEG/GIF — convert WebP dll dulu
    buffer = await ensureDiscordImage(buffer);

    // Strategy: upload as temporary emoji to get Discord CDN URL, then delete emoji
    const tempName = `img_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
    const emoji = await guild.emojis.create({ attachment: buffer, name: tempName });
    const cdnUrl = emoji.url; // https://cdn.discordapp.com/emojis/...

    // Delete the temporary emoji (we only need the URL)
    await emoji.delete('Temporary upload for image URL');

    res.json({ ok: true, url: cdnUrl, size: buffer.length });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ===== Manual Delivery =====
apiRouter.post('/manual-delivery', async (req, res) => {
  const { guild_id, user_id, product_id, quantity, note } = req.body;
  if (!guild_id || !user_id || !product_id) {
    return res.status(400).json({ error: 'guild_id, user_id, product_id required' });
  }
  if (!ensureGuild(req, res, guild_id)) return;

  // Quantity wajib integer positif murni (tolak "abc", "1.5", -1, 0, kosong)
  const qtyStr = String(quantity ?? '').trim();
  if (!/^\d+$/.test(qtyStr)) {
    return res.status(400).json({ error: 'quantity harus angka bulat positif' });
  }
  const qty = parseInt(qtyStr, 10);
  if (qty < 1 || qty > 10) return res.status(400).json({ error: 'quantity harus 1-10' });

  const client = req.app.get('discord-client');
  try {
    // Get product
    const product = db.prepare('SELECT * FROM products WHERE id = ? AND guild_id = ?').get(product_id, guild_id);
    if (!product) return res.status(404).json({ error: 'Product not found' });

    // Get available stock
    const stocks = db.prepare('SELECT * FROM stock WHERE product_id = ? AND sold = 0 LIMIT ?').all(product_id, qty);
    if (stocks.length < qty) {
      return res.status(400).json({ error: `Not enough stock. Available: ${stocks.length}, requested: ${qty}` });
    }

    // Mark stock as sold
    const tx = db.transaction(() => {
      for (const stock of stocks) {
        db.prepare('UPDATE stock SET sold = 1, sold_to = ?, sold_at = unixepoch() WHERE id = ?')
          .run(user_id, stock.id);
      }
    });
    tx();

    // Prepare delivery content
    const deliveryContent = stocks.map(s => s.content).join('\n');

    // Send DM to user
    try {
      const { EmbedBuilder } = await import('discord.js');
      const user = await client.users.fetch(user_id);
      const guild = await client.guilds.fetch(guild_id);

      const embed = new EmbedBuilder()
        .setTitle('📦 Manual Delivery')
        .setColor(0x10b981)
        .addFields(
          { name: 'Produk', value: product.name, inline: true },
          { name: 'Quantity', value: `${qty}`, inline: true },
          { name: 'Dari', value: 'Dashboard Admin', inline: true },
        )
        .setFooter({ text: `Guild: ${guild.name}` })
        .setTimestamp();

      // Susun deskripsi: note (kalau ada) + isi item, dua-duanya pakai code block
      const descParts = [];
      if (note && note.trim()) descParts.push('📝 **Note:**\n```\n' + note.trim() + '\n```');
      descParts.push('📦 **Item:**\n```\n' + deliveryContent + '\n```');
      embed.setDescription(descParts.join('\n'));

      await user.send({ embeds: [embed] });

      // Audit log
      db.prepare('INSERT INTO audit_log (guild_id, user_id, action, data) VALUES (?, ?, ?, ?)')
        .run(guild_id, 'dashboard', 'manual_delivery', JSON.stringify({
          target_user: user_id,
          product_id,
          product_name: product.name,
          quantity: qty,
          note: note || null,
          stock_ids: stocks.map(s => s.id),
        }));

      res.json({ ok: true, delivered: qty, user_tag: user.tag });
    } catch (dmError) {
      // DM failed - rollback stock
      const rollback = db.transaction(() => {
        for (const stock of stocks) {
          db.prepare('UPDATE stock SET sold = 0, sold_to = NULL, sold_at = NULL WHERE id = ?').run(stock.id);
        }
      });
      rollback();

      return res.status(500).json({ error: `Failed to send DM: ${dmError.message}` });
    }
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// Get manual delivery log
apiRouter.get('/manual-delivery-log', (req, res) => {
  const { guild_id } = req.query;
  if (!ensureGuild(req, res, guild_id)) return;
  const logs = db.prepare(`
    SELECT * FROM audit_log
    WHERE guild_id = ? AND action = 'manual_delivery'
    ORDER BY created_at DESC LIMIT 50
  `).all(guild_id);

  const parsed = logs.map(l => ({
    ...l,
    data: JSON.parse(l.data),
    created_at_formatted: new Date(l.created_at * 1000).toLocaleString('id-ID'),
  }));

  res.json(parsed);
});

// ===== Payment Config (per-guild) =====
// GET: baca config — key TIDAK pernah dikirim plaintext, cuma status & mask.
apiRouter.get('/payment-config', (req, res) => {
  const { guild_id } = req.query;
  if (!ensureGuild(req, res, guild_id)) return;
  const c = getPaymentConfig(guild_id);
  if (!c) {
    return res.json({
      tripay_enabled: 0, midtrans_enabled: 0, pakasir_enabled: 0, auto_delivery: 1,
      tripay_configured: false, midtrans_configured: false, pakasir_configured: false,
      tripay_merchant_code: '', midtrans_client_key: '', midtrans_is_production: 0,
      pakasir_slug: '', manual_methods: '', qris_image_url: '',
    });
  }
  res.json({
    tripay_enabled: c.tripay_enabled,
    midtrans_enabled: c.midtrans_enabled,
    pakasir_enabled: c.pakasir_enabled || 0,
    auto_delivery: c.auto_delivery,
    // status terisi (tanpa bocorin nilai)
    tripay_configured: !!(c.tripay_api_key_enc && c.tripay_private_key_enc),
    midtrans_configured: !!c.midtrans_server_key_enc,
    pakasir_configured: !!(c.pakasir_slug && c.pakasir_api_key_enc),
    tripay_api_key_mask: c.tripay_api_key_enc ? maskSecret(decryptSecret(c.tripay_api_key_enc)) : '',
    midtrans_server_key_mask: c.midtrans_server_key_enc ? maskSecret(decryptSecret(c.midtrans_server_key_enc)) : '',
    pakasir_api_key_mask: c.pakasir_api_key_enc ? maskSecret(decryptSecret(c.pakasir_api_key_enc)) : '',
    // non-secret boleh tampil
    tripay_merchant_code: c.tripay_merchant_code || '',
    midtrans_client_key: c.midtrans_client_key || '',
    midtrans_is_production: c.midtrans_is_production || 0,
    pakasir_slug: c.pakasir_slug || '',
    manual_methods: c.manual_methods || '',
    qris_image_url: c.qris_image_url || '',
  });
});

// POST: simpan config. Key dienkripsi AES sebelum disimpan.
// Field key yang dikirim KOSONG = pertahankan key lama (jangan timpa).
apiRouter.post('/payment-config', (req, res) => {
  const b = req.body || {};
  const guild_id = b.guild_id;
  if (!guild_id) return res.status(400).json({ error: 'guild_id required' });
  if (!ensureGuild(req, res, guild_id)) return;

  const fields = {
    tripay_enabled: b.tripay_enabled ? 1 : 0,
    midtrans_enabled: b.midtrans_enabled ? 1 : 0,
    pakasir_enabled: b.pakasir_enabled ? 1 : 0,
    auto_delivery: b.auto_delivery ? 1 : 0,
    tripay_merchant_code: b.tripay_merchant_code || null,
    midtrans_client_key: b.midtrans_client_key || null,
    midtrans_is_production: b.midtrans_is_production ? 1 : 0,
    pakasir_slug: b.pakasir_slug || null,
    manual_methods: b.manual_methods || null,
    qris_image_url: b.qris_image_url || null,
  };

  // Key: hanya update kalau dikirim non-kosong (biar gak kehapus pas user gak isi ulang)
  if (b.tripay_api_key && b.tripay_api_key.trim()) fields.tripay_api_key_enc = encryptSecret(b.tripay_api_key.trim());
  if (b.tripay_private_key && b.tripay_private_key.trim()) fields.tripay_private_key_enc = encryptSecret(b.tripay_private_key.trim());
  if (b.midtrans_server_key && b.midtrans_server_key.trim()) fields.midtrans_server_key_enc = encryptSecret(b.midtrans_server_key.trim());
  if (b.pakasir_api_key && b.pakasir_api_key.trim()) fields.pakasir_api_key_enc = encryptSecret(b.pakasir_api_key.trim());

  // Guard: kalau enable gateway tapi belum ada key sama sekali → tolak (cegah config setengah jadi)
  const cur = getPaymentConfig(guild_id);
  const tripayHasKey = fields.tripay_api_key_enc || cur?.tripay_api_key_enc;
  const tripayHasPriv = fields.tripay_private_key_enc || cur?.tripay_private_key_enc;
  if (fields.tripay_enabled && !(tripayHasKey && tripayHasPriv && fields.tripay_merchant_code)) {
    return res.status(400).json({ error: 'Tripay aktif butuh API Key, Private Key, dan Merchant Code' });
  }
  const midtransHasKey = fields.midtrans_server_key_enc || cur?.midtrans_server_key_enc;
  if (fields.midtrans_enabled && !midtransHasKey) {
    return res.status(400).json({ error: 'Midtrans aktif butuh Server Key' });
  }
  const pakasirHasKey = fields.pakasir_api_key_enc || cur?.pakasir_api_key_enc;
  if (fields.pakasir_enabled && !(pakasirHasKey && fields.pakasir_slug)) {
    return res.status(400).json({ error: 'Pakasir aktif butuh API Key dan Project Slug' });
  }

  upsertPaymentConfig(guild_id, fields);
  res.json({ ok: true });
});

// ===== Emoji =====
apiRouter.get('/emojis', async (req, res) => {
  const { guild_id } = req.query;
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const guild = await client.guilds.fetch(guild_id);
    await guild.emojis.fetch();
    const emojis = [...guild.emojis.cache.values()].map(e => ({
      id: e.id,
      name: e.name,
      url: e.url,
      animated: e.animated,
      tag: `<${e.animated ? 'a' : ''}:${e.name}:${e.id}>`,
    }));
    res.json(emojis);
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

apiRouter.post('/emojis', async (req, res) => {
  const { guild_id, name, url, image_data } = req.body;
  if (!guild_id || !name) return res.status(400).json({ error: 'guild_id and name required' });
  if (!url && !image_data) return res.status(400).json({ error: 'url or image_data required' });
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const guild = await client.guilds.fetch(guild_id);
    const cleanName = name.replace(/[^a-z0-9_]/gi, '_').slice(0, 32);

    let buf;
    if (image_data) {
      // File upload: data URL "data:image/<fmt>;base64,...."
      const matches = image_data.match(/^data:image\/(\w+);base64,(.+)$/);
      if (!matches) throw new Error('Invalid image data format');
      buf = Buffer.from(matches[2], 'base64');
    } else {
      const r = await fetch(url);
      if (!r.ok) throw new Error(`Image fetch HTTP ${r.status}`);
      buf = Buffer.from(await r.arrayBuffer());
    }

    // Terima sampai 10 MB (Discord limit 256 KB, kita resize otomatis di bawah)
    if (buf.length > 10 * 1024 * 1024) throw new Error(`File ${(buf.length/1024/1024).toFixed(1)}MB > 10MB limit`);

    // Convert WebP dll -> PNG/GIF, lalu auto-resize ke bawah 256 KB (transparansi terjaga)
    buf = await ensureDiscordEmoji(buf);
    if (buf.length > 256 * 1024) throw new Error(`Gagal compress di bawah 256KB (hasil ${(buf.length/1024).toFixed(0)}KB)`);
    const emoji = await guild.emojis.create({ attachment: buf, name: cleanName });
    res.json({ id: emoji.id, name: emoji.name, tag: `<${emoji.animated ? 'a' : ''}:${emoji.name}:${emoji.id}>` });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

apiRouter.delete('/emojis/:id', async (req, res) => {
  const { guild_id } = req.query;
  if (!ensureGuild(req, res, guild_id)) return;
  const client = req.app.get('discord-client');
  try {
    const guild = await client.guilds.fetch(guild_id);
    await guild.emojis.delete(req.params.id);
    res.json({ ok: true });
  } catch (e) {
    res.status(500).json({ error: e.message });
  }
});

// ===== Guild Config (emojis, ticket color, etc.) =====
apiRouter.get('/guild-config', (req, res) => {
  const { guild_id } = req.query;
  if (!ensureGuild(req, res, guild_id)) return;
  const cfg = getGuildConfig(guild_id);
  res.json({
    emoji_price: cfg.emoji_price || '',
    emoji_stock: cfg.emoji_stock || '',
    emoji_sku: cfg.emoji_sku || '',
    emoji_category: cfg.emoji_category || '',
    emoji_description: cfg.emoji_description || '',
    emoji_order: cfg.emoji_order || '',
    ticket_color: cfg.ticket_color || '#5865F2',
    ticket_category_id: cfg.ticket_category_id || '',
    log_channel_id: cfg.log_channel_id || '',
    staff_role_id: cfg.staff_role_id || '',
  });
});

apiRouter.put('/guild-config', (req, res) => {
  const { guild_id } = req.body;
  if (!ensureGuild(req, res, guild_id)) return;
  const fields = {};
  const allowed = ['emoji_price','emoji_stock','emoji_sku','emoji_category','emoji_description','emoji_order','ticket_color','ticket_category_id','log_channel_id','staff_role_id'];
  for (const k of allowed) {
    if (k in req.body) fields[k] = req.body[k] || null;
  }
  if (Object.keys(fields).length) updateGuildConfig(guild_id, fields);
  res.json({ ok: true });
});
