'use strict';
const brain = require('../brain');
const { chat } = require('../chat');
const crypto = require('crypto');
const { randomUUID: uuidv4 } = require('node:crypto');

// Agent identity
let agentId = null;

function getAgentId() {
  if (agentId) return agentId;
  const ownerName = brain.getOwnerName();
  agentId = 'wall-e-' + (ownerName || 'unknown').toLowerCase().replace(/\s+/g, '-');
  return agentId;
}

// Reset cached agentId (useful for testing)
function _resetAgentId() {
  agentId = null;
}

// Paired agents registry
const pairedAgents = new Map(); // agentId -> { endpoint, owner }

function pairAgent(remoteAgentId, endpoint, owner) {
  pairedAgents.set(remoteAgentId, { endpoint, owner });
  console.log(`[agent-api] Paired with ${remoteAgentId} at ${endpoint}`);
}

function unpairAgent(remoteAgentId) {
  pairedAgents.delete(remoteAgentId);
}

function listPairedAgents() {
  return Array.from(pairedAgents.entries()).map(([id, info]) => ({ id, ...info }));
}

/**
 * Handle an inbound exchange request from another WALL-E agent.
 */
async function handleInboundExchange(request) {
  const { from, intent, topic, message, context } = request;

  if (!from || !from.agent_id) {
    return { error: 'Missing from.agent_id' };
  }

  // Check if this agent is paired
  if (!pairedAgents.has(from.agent_id)) {
    return { error: 'Unknown agent. Not paired.' };
  }

  // Look up the person this agent represents
  const people = brain.listPeople({});
  const person = people.find(p => {
    const aliases = p.aliases ? JSON.parse(p.aliases) : [];
    return p.name === from.owner || aliases.includes(from.owner);
  });

  // Load persona for this person (or use default)
  let persona = null;
  if (person) {
    persona = brain.getPersonaForPerson(person.id);
  }

  // Apply sharing rules
  const sharingRules = persona ? JSON.parse(persona.sharing_rules || '{}') : {};
  const boundaries = persona ? JSON.parse(persona.boundaries || '{}') : {};
  const shareable = sharingRules.shareable || ['work_projects', 'availability', 'technical_opinions'];
  const neverShare = (sharingRules.never_share || ['personal_health', 'salary', 'job_search', 'private_messages'])
    .concat(boundaries.never_share || []);

  // Get relevant knowledge filtered by sharing rules
  const allKnowledge = brain.findKnowledge({ status: 'active' });
  const sharedKnowledge = allKnowledge.filter(k => {
    if (neverShare.includes(k.category)) return false;
    return shareable.includes(k.category) || shareable.includes('all');
  });
  const withheldKnowledge = allKnowledge.filter(k => !sharedKnowledge.includes(k));

  // Generate response using chat with persona context
  const ownerName = brain.getOwnerName();
  const tone = persona?.tone || 'professional';

  let responseText;
  try {
    const result = await chat(
      `[Agent exchange from ${from.owner}'s agent] Topic: ${topic || 'general'}. Message: ${message}. Respond in a ${tone} tone. Only share information that ${ownerName} would share with ${from.owner}.`,
      { channel: 'agent-exchange' }
    );
    responseText = result.reply;
  } catch (err) {
    responseText = 'Unable to process request at this time.';
  }

  // Log the exchange
  const exchangeId = uuidv4();
  try {
    brain.getDb().prepare(`
      INSERT INTO agent_exchanges (id, direction, remote_agent_id, person_id, persona_id, topic, message_in, message_out, shared_knowledge, withheld, confidence, created_at)
      VALUES (?, 'inbound', ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
    `).run(
      exchangeId,
      from.agent_id,
      person?.id || null,
      persona?.id || null,
      topic || null,
      message,
      responseText,
      JSON.stringify(sharedKnowledge.map(k => ({ subject: k.subject, predicate: k.predicate, object: k.object }))),
      JSON.stringify(withheldKnowledge.map(k => ({ subject: k.subject, category: k.category }))),
      0.7
    );
  } catch (e) {
    // Log failure silently
  }

  return {
    from: { agent_id: getAgentId(), owner: ownerName },
    intent: 'respond',
    topic: topic || null,
    message: responseText,
    shared_knowledge: sharedKnowledge.slice(0, 10).map(k => ({
      fact: `${k.subject} ${k.predicate} ${k.object}`,
      confidence: k.confidence,
    })),
    withheld: withheldKnowledge.length > 0,
  };
}

/**
 * Send an outbound exchange to a paired agent.
 */
async function sendExchange(remoteAgentId, message, topic) {
  const remote = pairedAgents.get(remoteAgentId);
  if (!remote) throw new Error(`Agent ${remoteAgentId} is not paired`);

  const ownerName = brain.getOwnerName();
  const payload = {
    from: { agent_id: getAgentId(), owner: ownerName },
    intent: 'query',
    topic: topic || null,
    message,
  };

  const res = await fetch(remote.endpoint + '/api/wall-e/agent/exchange', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
    signal: AbortSignal.timeout(30000),
  });

  if (!res.ok) throw new Error(`Agent exchange failed: ${res.status}`);
  const response = await res.json();

  // Log outbound exchange
  try {
    brain.getDb().prepare(`
      INSERT INTO agent_exchanges (id, direction, remote_agent_id, topic, message_in, message_out, created_at)
      VALUES (?, 'outbound', ?, ?, ?, ?, datetime('now'))
    `).run(uuidv4(), remoteAgentId, topic || null, message, response.message || '');
  } catch (e) {
    // Log failure silently
  }

  return response;
}

module.exports = {
  getAgentId, _resetAgentId, pairAgent, unpairAgent, listPairedAgents,
  handleInboundExchange, sendExchange,
};
