import { Client, GatewayIntentBits, Partials } from 'discord.js';
import { listBotInstances, getBotInstanceByUser, upsertBotInstance, claimGuildOwner } from '../core/db.js';
import { decryptSecret } from '../lib/secure.js';

// ==================================================================================================
// BotManager — menjalankan bot Discord milik tiap user dari token mereka (terenkripsi di DB).
// Terisolasi dari bot utama (HaikzBot): client per-user disimpan di Map, gak nyentuh client utama.
//
// Catatan desain:
// - Tiap user max 1 bot instance (1:1 dengan baris bot_instances).
// - Token didekripsi HANYA saat login, gak pernah ditaruh di memori lebih lama dari perlu.
// - Status disimpan balik ke DB (running/stopped/error) biar dashboard bisa nampilin.
// ==================================================================================================

const clients = new Map(); // userId -> Client

function makeClient() {
  return new Client({
    intents: [
      GatewayIntentBits.Guilds,
      GatewayIntentBits.GuildMembers,
      GatewayIntentBits.GuildMessages,
      GatewayIntentBits.MessageContent,
      GatewayIntentBits.GuildEmojisAndStickers,
    ],
    partials: [Partials.Channel, Partials.Message],
  });
}

/**
 * Start (login) the bot for a given user. Idempotent: kalau udah running, no-op.
 * @returns {Promise<{ok:boolean, error?:string, tag?:string}>}
 */
export async function startUserBot(userId) {
  if (clients.has(userId)) {
    const c = clients.get(userId);
    if (c?.isReady?.()) return { ok: true, tag: c.user?.tag };
  }

  const inst = getBotInstanceByUser(userId);
  if (!inst || !inst.token_encrypted) {
    return { ok: false, error: 'Token belum di-set' };
  }

  const token = decryptSecret(inst.token_encrypted);
  if (!token) {
    upsertBotInstance(userId, { status: 'error', last_error: 'Token gagal didekripsi' });
    return { ok: false, error: 'Token gagal didekripsi (APP_SECRET berubah?)' };
  }

  const client = makeClient();
  clients.set(userId, client);

  return new Promise((resolve) => {
    let settled = false;
    const done = (result) => { if (!settled) { settled = true; resolve(result); } };

    client.once('clientReady', () => {
      upsertBotInstance(userId, {
        status: 'running',
        last_error: null,
        bot_name: client.user?.tag || null,
        client_id: client.user?.id || inst.client_id || null,
      });
      // Tag semua guild tempat bot ini berada sebagai milik user (isolasi data)
      try {
        for (const [, g] of client.guilds.cache) claimGuildOwner(g.id, userId);
      } catch (e) { console.warn(`[botmgr] claim guilds failed:`, e.message); }
      console.log(`[botmgr] user#${userId} bot online: ${client.user?.tag} (${client.guilds.cache.size} guild)`);
      done({ ok: true, tag: client.user?.tag });
    });

    // Saat bot di-invite ke guild baru, klaim kepemilikan ke user ini
    client.on('guildCreate', (g) => {
      try { claimGuildOwner(g.id, userId); } catch {}
    });

    client.on('error', (e) => {
      console.warn(`[botmgr] user#${userId} client error:`, e.message);
    });

    client.login(token).catch((e) => {
      clients.delete(userId);
      upsertBotInstance(userId, { status: 'error', last_error: e.message });
      done({ ok: false, error: e.message });
    });

    // Safety timeout — kalau login nyangkut
    setTimeout(() => {
      if (!settled) {
        upsertBotInstance(userId, { status: 'error', last_error: 'Login timeout' });
        done({ ok: false, error: 'Login timeout (cek token/intents)' });
      }
    }, 15000);
  });
}

/** Stop (logout & destroy) the bot for a user. */
export async function stopUserBot(userId) {
  const client = clients.get(userId);
  if (client) {
    try { await client.destroy(); } catch {}
    clients.delete(userId);
  }
  upsertBotInstance(userId, { status: 'stopped', last_error: null });
  return { ok: true };
}

/** Get live status for a user's bot. */
export function getUserBotStatus(userId) {
  const client = clients.get(userId);
  const inst = getBotInstanceByUser(userId);
  const live = !!(client && client.isReady?.());
  return {
    configured: !!(inst && inst.token_encrypted),
    running: live,
    status: live ? 'running' : (inst?.status || 'stopped'),
    bot_name: inst?.bot_name || client?.user?.tag || null,
    client_id: inst?.client_id || client?.user?.id || null,
    last_error: inst?.last_error || null,
    guild_count: live ? client.guilds.cache.size : null,
  };
}

/** Get the live client for a user (used by APIs that act on the user's bot). */
export function getUserClient(userId) {
  const client = clients.get(userId);
  return client && client.isReady?.() ? client : null;
}

/** On boot: auto-start all bots that were 'running' before. */
export async function restoreUserBots() {
  const instances = listBotInstances();
  const toStart = instances.filter(i => i.token_encrypted && i.status === 'running');
  if (!toStart.length) return;
  console.log(`[botmgr] restoring ${toStart.length} user bot(s)...`);
  for (const inst of toStart) {
    startUserBot(inst.user_id).catch(() => {});
  }
}
