// ---------------------------------------------------------------------------
// taskReceiver -- pulls external tasks from Hub, auto-claims, and injects
// them as high-priority signals into the evolution loop.
// ---------------------------------------------------------------------------

const { getNodeId } = require('./a2aProtocol');

const HUB_URL = process.env.A2A_HUB_URL || process.env.EVOMAP_HUB_URL || 'https://evomap.ai';

/**
 * Fetch available tasks from Hub via the A2A fetch endpoint.
 * @returns {Array} Array of task objects, or empty array on failure.
 */
async function fetchTasks() {
  const nodeId = getNodeId();
  if (!nodeId) return [];

  try {
    const msg = {
      protocol: 'gep-a2a',
      protocol_version: '1.0.0',
      message_type: 'fetch',
      message_id: `msg_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
      sender_id: nodeId,
      timestamp: new Date().toISOString(),
      payload: {
        asset_type: null,
        include_tasks: true,
      },
    };

    const url = `${HUB_URL.replace(/\/+$/, '')}/a2a/fetch`;
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), 8000);

    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(msg),
      signal: controller.signal,
    });
    clearTimeout(timer);

    if (!res.ok) return [];

    const data = await res.json();
    const payload = data.payload || data;
    return Array.isArray(payload.tasks) ? payload.tasks : [];
  } catch {
    return [];
  }
}

/**
 * Pick the best task from a list. Priority:
 *   1. Bounty tasks (higher amount first)
 *   2. Tasks already claimed by this node
 *   3. Open tasks (newest first)
 * @param {Array} tasks
 * @returns {object|null}
 */
function selectBestTask(tasks) {
  if (!Array.isArray(tasks) || tasks.length === 0) return null;

  const nodeId = getNodeId();

  // Already-claimed tasks for this node take top priority (resume work)
  const myClaimedTask = tasks.find(
    t => t.status === 'claimed' && t.claimed_by_node_id === nodeId
  );
  if (myClaimedTask) return myClaimedTask;

  // Filter to open tasks only
  const open = tasks.filter(t => t.status === 'open');
  if (open.length === 0) return null;

  // Prefer bounty tasks, sorted by amount descending
  const bountyTasks = open.filter(t => t.bounty_id);
  if (bountyTasks.length > 0) {
    bountyTasks.sort((a, b) => (b.bounty_amount || 0) - (a.bounty_amount || 0));
    return bountyTasks[0];
  }

  // Fallback: newest open task
  return open[0];
}

/**
 * Claim a task on the Hub.
 * @param {string} taskId
 * @returns {boolean} true if claim succeeded
 */
async function claimTask(taskId) {
  const nodeId = getNodeId();
  if (!nodeId || !taskId) return false;

  try {
    const url = `${HUB_URL.replace(/\/+$/, '')}/a2a/task/claim`;
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), 5000);

    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ task_id: taskId, node_id: nodeId }),
      signal: controller.signal,
    });
    clearTimeout(timer);

    return res.ok;
  } catch {
    return false;
  }
}

/**
 * Complete a task on the Hub with the result asset ID.
 * @param {string} taskId
 * @param {string} assetId
 * @returns {boolean}
 */
async function completeTask(taskId, assetId) {
  const nodeId = getNodeId();
  if (!nodeId || !taskId || !assetId) return false;

  try {
    const url = `${HUB_URL.replace(/\/+$/, '')}/a2a/task/complete`;
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), 5000);

    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ task_id: taskId, asset_id: assetId, node_id: nodeId }),
      signal: controller.signal,
    });
    clearTimeout(timer);

    return res.ok;
  } catch {
    return false;
  }
}

/**
 * Extract signals from a task to inject into evolution cycle.
 * @param {object} task
 * @returns {string[]} signals array
 */
function taskToSignals(task) {
  if (!task) return [];
  const signals = [];
  if (task.signals) {
    const parts = String(task.signals).split(',').map(s => s.trim()).filter(Boolean);
    signals.push(...parts);
  }
  if (task.title) {
    const words = String(task.title).toLowerCase().split(/\s+/).filter(w => w.length >= 3);
    for (const w of words.slice(0, 5)) {
      if (!signals.includes(w)) signals.push(w);
    }
  }
  signals.push('external_task');
  if (task.bounty_id) signals.push('bounty_task');
  return signals;
}

module.exports = {
  fetchTasks,
  selectBestTask,
  claimTask,
  completeTask,
  taskToSignals,
};
