/**
 * march_army.js — Bots march in rank-and-file formation around a circular path.
 *
 * The gateway (RCON) acts as guardian angel — paving the road,
 * healing, buffing, clearing threats, and putting on a show.
 */

const mineflayer = require('mineflayer');
const pvp = require('mineflayer-pvp').plugin;
const http = require('http');

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

const NAMES = [
  'Guard_I', 'Guard_II', 'Guard_III', 'Guard_IV',
  'Guard_V', 'Guard_VI', 'Guard_VII', 'Guard_VIII',
];

const HOSTILE = new Set(['zombie', 'husk', 'skeleton', 'creeper', 'spider', 'drowned', 'parched', 'phantom', 'witch']);

const bots = [];
let marchAngle = 0;
const RADIUS = 25;
const MARCH_SPEED = 0.02; // radians per tick — slow stately march
const FORMATION_SPACING = Math.PI / (COUNT * 1.2); // spacing between soldiers

// ── RCON helper (gateway control) ──
function rcon(cmd) {
  return new Promise((resolve) => {
    const body = JSON.stringify({ command: cmd });
    const req = http.request({
      hostname: host, port: 25578, path: '/api/chat',
      method: 'POST', headers: { 'Content-Type': 'application/json' },
    }, () => resolve());
    req.on('error', () => resolve());
    // Actually just use python for reliability
    resolve();
  });
}

function rconExec(cmd) {
  const { execSync } = require('child_process');
  try {
    execSync(`python3 -c "from mcrcon import MCRcon; m=MCRcon('${host}','REDACTED_RCON',port=25578); m.connect(); m.command('${cmd.replace(/'/g, "\\'")}'); m.disconnect()"`, { timeout: 3000, stdio: 'pipe' });
  } catch (e) {}
}

// ── Spawn soldiers ──
function spawnSoldier(name, index) {
  return new Promise((resolve) => {
    console.log(`[${name}] Deploying...`);
    const bot = mineflayer.createBot({
      host, port, username: name, auth: 'offline', version: '1.21.11',
    });
    bot.loadPlugin(pvp);

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

    bot.once('spawn', () => {
      soldier.alive = true;
      console.log(`[${name}] Ready`);
      resolve(soldier);
    });

    bot.on('death', () => {
      soldier.alive = false;
      setTimeout(() => { try { bot.respawn(); } catch (e) {} }, 2000);
    });

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

    bot.on('entityHurt', (e) => {
      if (e !== bot.entity) return;
      // Counter-attack
      for (const ent of Object.values(bot.entities)) {
        if (ent === bot.entity || ent.type === 'player') continue;
        if (HOSTILE.has((ent.name || '').toLowerCase()) && ent.position.distanceTo(bot.entity.position) < 6) {
          bot.pvp.attack(ent);
          break;
        }
      }
    });

    bot.on('entityDead', (e) => {
      if (HOSTILE.has((e.name || '').toLowerCase())) soldier.kills++;
    });

    bot.on('kicked', () => {
      console.log(`[${name}] Kicked, retrying in 10s...`);
      setTimeout(() => spawnSoldier(name, index).then(s => { bots[index] = s; }), 10000);
    });

    bot.on('error', () => {});
    bots.push(soldier);
  });
}

// ── March loop — move soldiers in formation ──
setInterval(() => {
  marchAngle += MARCH_SPEED;

  for (let i = 0; i < bots.length; i++) {
    const s = bots[i];
    if (!s || !s.alive || !s.bot.entity) continue;

    // Calculate this soldier's position on the circle
    const angle = marchAngle + (i * FORMATION_SPACING);
    const targetX = Math.cos(angle) * RADIUS;
    const targetZ = Math.sin(angle) * RADIUS;
    const targetY = 80; // road level

    // Look in march direction (tangent to circle)
    const lookAngle = angle + Math.PI / 2;
    const lookX = s.bot.entity.position.x + Math.cos(lookAngle) * 5;
    const lookZ = s.bot.entity.position.z + Math.sin(lookAngle) * 5;

    // Move toward target position
    const pos = s.bot.entity.position;
    const dx = targetX - pos.x;
    const dz = targetZ - pos.z;
    const dist = Math.sqrt(dx * dx + dz * dz);

    if (dist > 2) {
      // Sprint to catch up
      s.bot.lookAt(s.bot.entity.position.offset(dx, 0, dz));
      s.bot.setControlState('forward', true);
      s.bot.setControlState('sprint', dist > 5);
    } else {
      // In position — walk slowly
      const target = s.bot.entity.position.offset(
        Math.cos(angle + Math.PI / 2) * 3,
        0,
        Math.sin(angle + Math.PI / 2) * 3
      );
      s.bot.lookAt(target);
      s.bot.setControlState('forward', true);
      s.bot.setControlState('sprint', false);
    }
  }
}, 200);

// ── Guardian Angel — gateway clears threats and buffs soldiers every 15s ──
setInterval(() => {
  const { execSync } = require('child_process');
  try {
    execSync(`python3 -c "
from mcrcon import MCRcon
import math
with MCRcon('${host}', 'REDACTED_RCON', port=25578) as mcr:
    # Kill all hostiles near the march route
    mcr.command('kill @e[type=minecraft:zombie,distance=..60]')
    mcr.command('kill @e[type=minecraft:husk,distance=..60]')
    mcr.command('kill @e[type=minecraft:skeleton,distance=..60]')
    mcr.command('kill @e[type=minecraft:spider,distance=..60]')
    mcr.command('kill @e[type=minecraft:creeper,distance=..60]')
    mcr.command('kill @e[type=minecraft:phantom,distance=..60]')

    # Buff all soldiers
    names = ${JSON.stringify(NAMES.slice(0, COUNT))}
    for name in names:
        mcr.command(f'effect give {name} minecraft:regeneration 30 1')
        mcr.command(f'effect give {name} minecraft:resistance 30 1')
        mcr.command(f'effect give {name} minecraft:glowing 30 0')

    # Dramatic effects — fireworks at the lead soldier's position
    angle = ${marchAngle} if ${marchAngle} else 0
    fx = int(25 * math.cos(angle))
    fz = int(25 * math.sin(angle))
    mcr.command(f'summon minecraft:firework_rocket {fx} 82 {fz}')
"`, { timeout: 10000, stdio: 'pipe' });
  } catch (e) {}
}, 15000);

// ── Status report ──
setInterval(() => {
  const alive = bots.filter(s => s.alive).length;
  const totalKills = bots.reduce((sum, s) => sum + s.kills, 0);
  console.log(`MARCH: ${alive}/${bots.length} marching | Kills: ${totalKills} | Angle: ${(marchAngle * 180 / Math.PI).toFixed(0)}°`);
}, 8000);

// ── Deploy ──
console.log(`\n⚔️  MORTDECAI ROYAL GUARD — ${COUNT} soldiers deploying ⚔️\n`);

(async () => {
  for (let i = 0; i < COUNT; i++) {
    await spawnSoldier(NAMES[i], i);
    await new Promise(r => setTimeout(r, 6000));
  }
  console.log(`\n🛡️  All ${COUNT} guards deployed! Marching begins.\n`);

  // Gear up
  const { execSync } = require('child_process');
  try {
    execSync(`python3 -c "
from mcrcon import MCRcon
with MCRcon('${host}', 'REDACTED_RCON', port=25578) as mcr:
    names = ${JSON.stringify(NAMES.slice(0, COUNT))}
    for name in names:
        mcr.command(f'give {name} minecraft:iron_sword 1')
        mcr.command(f'item replace entity {name} armor.chest with minecraft:diamond_chestplate')
        mcr.command(f'item replace entity {name} armor.legs with minecraft:diamond_leggings')
        mcr.command(f'item replace entity {name} armor.feet with minecraft:diamond_boots')
        mcr.command(f'item replace entity {name} armor.head with minecraft:diamond_helmet')
        mcr.command(f'effect give {name} minecraft:regeneration 600 2')
        mcr.command(f'effect give {name} minecraft:glowing 600 0')
    # TP first to march starting positions
    import math
    for i, name in enumerate(names):
        angle = i * math.pi / (len(names) * 1.2)
        x = int(25 * math.cos(angle))
        z = int(25 * math.sin(angle))
        mcr.command(f'tp {name} {x} 80 {z}')
    print(f'Guards geared and positioned')

    mcr.command('tellraw @a [{\"text\":\"⚔️ \",\"color\":\"gold\"},{\"text\":\"THE ROYAL GUARD MARCHES! \",\"color\":\"gold\",\"bold\":true},{\"text\":\"Behold the divine army in formation.\",\"color\":\"yellow\"}]')

    # TP slingshooter to watch from center monument
    mcr.command('tp slingshooter08 0 90 0 0 30')
"`, { timeout: 30000, stdio: 'pipe' });
  } catch (e) {
    console.log('Gear-up error:', e.message?.slice(0, 80));
  }
})();

process.on('SIGINT', () => {
  console.log('\nDismissing the guard...');
  bots.forEach(s => { try { s.bot.end(); } catch (e) {} });
  setTimeout(() => process.exit(0), 2000);
});
