/**
 * bot_army.js — Spawn an army of combat bots.
 *
 * Each bot runs autonomous combat with mineflayer-pvp.
 * They attack all hostiles but never each other.
 * Reports collective stats.
 *
 * Usage: node bot_army.js [count] [host] [port]
 */

const mineflayer = require('mineflayer');
const pvp = require('mineflayer-pvp').plugin;
const armorManager = require('mineflayer-armor-manager');
const pathfinder = require('mineflayer-pathfinder');
const { GoalNear } = require('mineflayer-pathfinder').goals;

const count = parseInt(process.argv[2] || '8', 10);
const host = process.argv[3] || '192.168.0.244';
const port = parseInt(process.argv[4] || '25567', 10);

const HOSTILE = new Set([
  'zombie', 'husk', 'skeleton', 'creeper', 'spider', 'cave_spider',
  'witch', 'enderman', 'pillager', 'vindicator', 'phantom',
  'drowned', 'stray', 'blaze', 'ghast', 'slime', 'magma_cube',
  'parched', 'camel_husk', 'zombie_villager',
]);

const NAMES = [
  'Soldier_Alpha', 'Soldier_Bravo', 'Soldier_Charlie', 'Soldier_Delta',
  'Soldier_Echo', 'Soldier_Foxtrot', 'Soldier_Golf', 'Soldier_Hotel',
  'Soldier_India', 'Soldier_Juliet', 'Soldier_Kilo', 'Soldier_Lima',
  'Soldier_Mike', 'Soldier_November', 'Soldier_Oscar', 'Soldier_Papa',
];

// Track all bot names so they don't attack each other
const armyNames = new Set(NAMES.slice(0, count));
armyNames.add('ClaudeBot');
armyNames.add('slingshooter08');
armyNames.add('OracleBot');

const army = [];
let totalKills = 0;
let totalDeaths = 0;

function spawnSoldier(name, index) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log(`[${name}] Spawning...`);

      const bot = mineflayer.createBot({
        host, port,
        username: name,
        auth: 'offline',
        version: '1.21.11',
      });

      bot.loadPlugin(pvp);
      bot.loadPlugin(armorManager);
      bot.loadPlugin(pathfinder.pathfinder);

      const soldier = { bot, name, kills: 0, deaths: 0, alive: false };

      bot.once('spawn', () => {
        soldier.alive = true;

        // Configure pathfinder
        try {
          const mcData = require('minecraft-data')(bot.version);
          const movements = new pathfinder.Movements(bot, mcData);
          movements.allowSprinting = true;
          movements.canDig = false;
          bot.pathfinder.setMovements(movements);
        } catch (e) {}

        console.log(`[${name}] Ready at (${Math.floor(bot.entity.position.x)}, ${Math.floor(bot.entity.position.y)}, ${Math.floor(bot.entity.position.z)})`);
        resolve(soldier);
      });

      // Respawn on death
      bot.on('death', () => {
        soldier.alive = false;
        soldier.deaths++;
        totalDeaths++;
        console.log(`[${name}] DIED (kills: ${soldier.kills}, deaths: ${soldier.deaths})`);
        setTimeout(() => { try { bot.respawn(); } catch (e) {} }, 2000);
      });

      bot.on('spawn', () => {
        if (soldier.deaths > 0) {
          soldier.alive = true;
        }
      });

      // Track kills
      bot.on('entityDead', (entity) => {
        const ename = (entity.name || entity.type || '').toLowerCase();
        if (HOSTILE.has(ename)) {
          soldier.kills++;
          totalKills++;
        }
      });

      // Counter-attack when hit
      bot.on('entityHurt', (entity) => {
        if (entity !== bot.entity) return;
        const attacker = findNearestHostile(bot, 8);
        if (attacker && !bot.pvp.target) {
          bot.pvp.attack(attacker);
        }
      });

      bot.on('kicked', (reason) => {
        console.log(`[${name}] Kicked: ${JSON.stringify(reason).slice(0, 80)}`);
      });

      bot.on('error', (err) => {
        console.error(`[${name}] Error: ${err.message}`);
      });

      army.push(soldier);
    }, index * 3000); // Stagger spawns by 3 seconds
  });
}

function findNearestHostile(bot, maxDist) {
  if (!bot.entity) return null;
  let nearest = null;
  let nearestDist = maxDist;
  for (const e of Object.values(bot.entities)) {
    if (e === bot.entity) continue;
    // Never attack army members or players
    if (e.type === 'player') continue;
    const ename = (e.name || e.type || '').toLowerCase();
    if (!HOSTILE.has(ename)) continue;
    const d = e.position.distanceTo(bot.entity.position);
    if (d < nearestDist) {
      nearestDist = d;
      nearest = e;
    }
  }
  return nearest;
}

// ── Autonomous combat loop for all bots ──
setInterval(() => {
  for (const soldier of army) {
    if (!soldier.alive || !soldier.bot.entity) continue;
    const bot = soldier.bot;
    const hp = bot.health;

    // Find nearest hostile
    const target = findNearestHostile(bot, 16);

    // Flee if critical
    if (hp < 5 && target) {
      bot.pvp.stop();
      const pos = bot.entity.position;
      const dx = pos.x - target.position.x;
      const dz = pos.z - target.position.z;
      const len = Math.sqrt(dx * dx + dz * dz) || 1;
      bot.lookAt(pos.offset((dx / len) * 10, 0, (dz / len) * 10));
      bot.setControlState('forward', true);
      bot.setControlState('sprint', true);
      setTimeout(() => {
        bot.setControlState('forward', false);
        bot.setControlState('sprint', false);
      }, 3000);
      continue;
    }

    // Attack nearest hostile
    if (target && !bot.pvp.target) {
      bot.pvp.attack(target);
    }

    // If no target but pvp active, stop
    if (!target && bot.pvp.target) {
      bot.pvp.stop();
    }
  }
}, 800);

// ── Status report every 10 seconds ──
setInterval(() => {
  const alive = army.filter(s => s.alive).length;
  const fighting = army.filter(s => s.bot.pvp?.target).length;
  console.log(`\n=== ARMY STATUS: ${alive}/${army.length} alive | ${fighting} fighting | Kills: ${totalKills} | Deaths: ${totalDeaths} ===`);
  for (const s of army) {
    if (!s.bot.entity) continue;
    const pos = s.bot.entity.position;
    const target = s.bot.pvp?.target;
    const status = !s.alive ? 'DEAD' : target ? `FIGHTING ${target.name || target.type}` : 'PATROLLING';
    console.log(`  [${s.name}] HP:${Math.round(s.bot.health)} K:${s.kills} D:${s.deaths} — ${status}`);
  }
}, 10000);

// ── Startup ──
console.log(`\n╔════════════════════════════════════════╗`);
console.log(`║  MORTDECAI BOT ARMY — ${count} SOLDIERS        ║`);
console.log(`║  Target: ${host}:${port}                ║`);
console.log(`║  Rules: Kill all hostiles, protect allies ║`);
console.log(`╚════════════════════════════════════════╝\n`);

// Whitelist soldiers (skip if dev server / no whitelist)
const { execSync } = require('child_process');
const rconPort = port === 25567 ? 25577 : 25578;
const rconPass = port === 25567 ? 'REDACTED_RCON' : 'REDACTED_RCON';
try {
  for (let i = 0; i < count; i++) {
    execSync(`python3 -c "from mcrcon import MCRcon; m=MCRcon('${host}','${rconPass}',port=${rconPort}); m.connect(); m.command('whitelist add ${NAMES[i]}'); m.disconnect()"`, { timeout: 5000, stdio: 'pipe' });
  }
  console.log(`Whitelisted ${count} soldiers`);
} catch (e) {
  console.log('Whitelist skipped (dev server or already done)');
}

// Spawn soldiers
(async () => {
  for (let i = 0; i < count; i++) {
    await spawnSoldier(NAMES[i], 0);
    await new Promise(r => setTimeout(r, 3000));
  }
  console.log(`\nAll ${count} soldiers deployed!`);

  // Gear them all up via RCON
  try {
    execSync(`python3 -c "
from mcrcon import MCRcon
with MCRcon('${host}', '${rconPass}', port=${rconPort}) as mcr:
    soldiers = ${JSON.stringify(NAMES.slice(0, count))}
    for name in soldiers:
        mcr.command(f'give {name} minecraft:iron_sword 1')
        mcr.command(f'give {name} minecraft:cooked_beef 16')
        mcr.command(f'item replace entity {name} armor.chest with minecraft:iron_chestplate')
        mcr.command(f'item replace entity {name} armor.legs with minecraft:iron_leggings')
        mcr.command(f'item replace entity {name} armor.feet with minecraft:iron_boots')
        mcr.command(f'item replace entity {name} armor.head with minecraft:iron_helmet')
        mcr.command(f'effect give {name} minecraft:regeneration 600 1')
    print(f'Geared up {len(soldiers)} soldiers')
"`, { timeout: 30000 });
  } catch (e) {
    console.log('Gear-up error:', e.message?.slice(0, 80));
  }
})();

// Graceful shutdown
process.on('SIGINT', () => {
  console.log(`\n\nFinal score: ${totalKills} kills, ${totalDeaths} deaths`);
  console.log('Disconnecting army...');
  army.forEach(s => { try { s.bot.end(); } catch (e) {} });
  setTimeout(() => process.exit(0), 2000);
});
