/**
 * combat_bot.js — Full combat-capable bot using mineflayer plugins.
 *
 * Uses:
 *   mineflayer-pvp        — combat AI (attack, strafe, shield)
 *   mineflayer-pathfinder  — A* navigation
 *   mineflayer-armor-manager — auto-equip best armor
 *   mineflayer-auto-eat    — auto-eat when hungry/hurt
 *
 * The bot autonomously fights, eats, equips armor, and pathfinds.
 * AI frames via stdin set high-level goals.
 */

const mineflayer = require('mineflayer');
const pathfinder = require('mineflayer-pathfinder');
const pvp = require('mineflayer-pvp').plugin;
const armorManager = require('mineflayer-armor-manager');
const autoEat = require('mineflayer-auto-eat').loader;
const { GoalNear, GoalFollow, GoalBlock } = require('mineflayer-pathfinder').goals;
const readline = require('readline');

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

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

// Load plugins
bot.loadPlugin(pathfinder.pathfinder);
bot.loadPlugin(pvp);
bot.loadPlugin(armorManager);
bot.loadPlugin(autoEat);

let deaths = 0;
let kills = 0;
let alive = false;

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',
]);

// ── Spawn setup ──
bot.once('spawn', () => {
  alive = true;
  deaths++;

  // Configure pathfinder
  const mcData = require('minecraft-data')(bot.version);
  const movements = new pathfinder.Movements(bot, mcData);
  movements.allowSprinting = true;
  movements.canDig = false; // Don't destroy blocks
  bot.pathfinder.setMovements(movements);

  // Configure auto-eat
  bot.autoEat.options = {
    priority: 'foodPoints',
    startAt: 16,
    bannedFood: [],
  };

  out({ event: 'ready', msg: 'Plugins loaded. Combat-ready.' });
  setTimeout(() => out(observe()), 3000);
});

bot.on('spawn', () => {
  if (deaths > 1) {
    alive = true;
    out({ event: 'respawn', deaths });
    setTimeout(() => out(observe()), 3000);
  }
});

// ── Combat events ──
bot.on('entityHurt', (entity) => {
  if (entity === bot.entity) {
    // I'm being hit — find attacker and fight back
    const attacker = nearestHostile(8);
    if (attacker && !bot.pvp.target) {
      out({ event: 'counter_attack', target: attacker.name || attacker.type, dist: Math.round(attacker.position.distanceTo(bot.entity.position)) });
      bot.pvp.attack(attacker);
    }
  }
});

bot.on('playerCollect', (collector, collected) => {
  if (collector === bot.entity) {
    out({ event: 'pickup', item: collected.name || 'item' });
  }
});

bot.on('death', () => {
  alive = false;
  deaths++;
  out({ event: 'death', deaths, kills });
  setTimeout(() => { try { bot.respawn(); } catch (e) {} }, 2000);
});

bot.on('chat', (username, message) => {
  if (username === bot.username) return;
  out({ event: 'chat', from: username, msg: message });
});

bot.on('kicked', (reason) => {
  out({ event: 'kicked', reason: typeof reason === 'object' ? JSON.stringify(reason) : String(reason) });
  process.exit(1);
});

// Track kills
bot.on('entityDead', (entity) => {
  const name = (entity.name || entity.type || '').toLowerCase();
  if (HOSTILE.has(name)) {
    kills++;
    out({ event: 'kill', target: name, totalKills: kills });
  }
});

// ── Autonomous combat loop ──
setInterval(() => {
  if (!alive || !bot.entity) return;

  const hp = bot.health;
  const nearest = nearestHostile(16);

  // If low HP and being attacked, flee
  if (hp < 6 && nearest && nearest.position.distanceTo(bot.entity.position) < 6) {
    bot.pvp.stop();
    fleeSmart(nearest);
    return;
  }

  // If hostile nearby and not already fighting, engage
  if (nearest && !bot.pvp.target) {
    const dist = nearest.position.distanceTo(bot.entity.position);
    if (dist < 10) {
      bot.pvp.attack(nearest);
    }
  }
}, 1000);

// ── Periodic status report ──
setInterval(() => {
  if (!alive) return;
  out(observe());
}, 6000);

// ── Helper functions ──

function nearestHostile(maxDist) {
  if (!bot.entity) return null;
  let nearest = null;
  let nearestDist = maxDist || 16;
  for (const e of Object.values(bot.entities)) {
    if (e === bot.entity) continue;
    const name = (e.name || e.type || '').toLowerCase();
    if (!HOSTILE.has(name)) continue;
    const d = e.position.distanceTo(bot.entity.position);
    if (d < nearestDist) {
      nearestDist = d;
      nearest = e;
    }
  }
  return nearest;
}

function fleeSmart(from) {
  if (!from || !bot.entity) return;
  const pos = bot.entity.position;
  const dx = pos.x - from.position.x;
  const dz = pos.z - from.position.z;
  const len = Math.sqrt(dx * dx + dz * dz) || 1;
  const fleeX = pos.x + (dx / len) * 30;
  const fleeZ = pos.z + (dz / len) * 30;

  try {
    bot.pathfinder.setGoal(new GoalNear(fleeX, pos.y, fleeZ, 2));
  } catch (e) {
    // Fallback: just sprint
    bot.setControlState('forward', true);
    bot.setControlState('sprint', true);
    setTimeout(() => {
      bot.setControlState('forward', false);
      bot.setControlState('sprint', false);
    }, 3000);
  }
}

function observe() {
  if (!bot.entity) return { alive: false };
  const pos = bot.entity.position;
  const mobs = [];

  for (const e of Object.values(bot.entities)) {
    if (e === bot.entity) continue;
    const d = Math.round(e.position.distanceTo(pos));
    if (d > 24) continue;
    const name = e.name || e.type;
    const hostile = HOSTILE.has((name || '').toLowerCase());
    if (e.type === 'player') {
      mobs.push({ type: 'player', name: e.username, dist: d });
    } else if (hostile || d < 10) {
      mobs.push({ type: name, dist: d, hostile });
    }
  }

  return {
    pos: { x: Math.floor(pos.x), y: Math.floor(pos.y), z: Math.floor(pos.z) },
    hp: Math.round(bot.health * 10) / 10,
    food: bot.food,
    day: (bot.time?.timeOfDay || 0) < 13000,
    inv: bot.inventory.items().map(i => `${i.name}x${i.count}`).join(', ') || 'empty',
    armor: [5, 6, 7, 8].map(s => bot.inventory.slots[s]?.name).filter(Boolean).join(', ') || 'none',
    weapon: bot.heldItem?.name || 'fist',
    fighting: bot.pvp.target ? (bot.pvp.target.name || bot.pvp.target.type) : null,
    mobs: mobs.sort((a, b) => a.dist - b.dist).slice(0, 8),
    kills,
    deaths,
  };
}

function out(obj) {
  console.log(JSON.stringify(obj));
}

// ── AI Frame commands ──
const rl = readline.createInterface({ input: process.stdin });
rl.on('line', (line) => {
  const cmd = line.trim();

  if (cmd === 'look') out(observe());
  else if (cmd === 'hunt') {
    // Actively seek and kill nearest hostile
    const target = nearestHostile(30);
    if (target) {
      bot.pvp.attack(target);
      out({ action: 'hunting', target: target.name || target.type, dist: Math.round(target.position.distanceTo(bot.entity.position)) });
    } else {
      out({ action: 'hunt', msg: 'no hostiles nearby' });
    }
  }
  else if (cmd === 'stop') { bot.pvp.stop(); bot.pathfinder.stop(); out({ action: 'stopped' }); }
  else if (cmd.startsWith('goto ')) {
    const [, x, y, z] = cmd.split(' ').map(Number);
    bot.pathfinder.setGoal(new GoalNear(x, y, z, 2));
    out({ action: 'navigating', target: { x, y, z } });
  }
  else if (cmd.startsWith('follow ')) {
    const name = cmd.slice(7);
    const player = bot.players[name];
    if (player?.entity) {
      bot.pathfinder.setGoal(new GoalFollow(player.entity, 3), true);
      out({ action: 'following', target: name });
    }
  }
  else if (cmd.startsWith('pray ')) { bot.chat(cmd); out({ action: 'pray' }); }
  else if (cmd.startsWith('sudo ')) { bot.chat(cmd); out({ action: 'sudo' }); }
  else if (cmd.startsWith('say ')) { bot.chat(cmd.slice(4)); }
  else if (cmd === 'quit') { bot.end(); process.exit(0); }
  else { out({ commands: ['look', 'hunt', 'stop', 'goto X Y Z', 'follow PLAYER', 'pray MSG', 'sudo CMD', 'say MSG', 'quit'] }); }
});
