/**
 * Agent Hierarchy Engine
 * 
 * Handles agent initialization, memory operations, inter-agent messaging,
 * escalation protocols, and interaction processing.
 */

import { prisma } from '@/lib/db';
import { AGENT_DEFINITIONS, getAgentDefinition } from './agents';

// ============================================
// AGENT LIFECYCLE
// ============================================

/**
 * Initialize all agents in the database from definitions.
 * Idempotent — safe to call multiple times.
 */
export async function initializeAgentHierarchy() {
  for (const def of AGENT_DEFINITIONS) {
    await prisma.domainAgent.upsert({
      where: { agentId: def.agentId },
      create: {
        agentId: def.agentId,
        name: def.name,
        title: def.title,
        domain: def.domain,
        personality: def.personality,
        systemPrompt: def.systemPrompt,
        parentAgentId: def.parentAgentId,
        moduleId: def.moduleId,
        avatarColor: def.avatarColor,
        capabilities: def.capabilities,
        status: 'active',
        config: { escalationTriggers: def.escalationTriggers },
      },
      update: {
        name: def.name,
        title: def.title,
        personality: def.personality,
        systemPrompt: def.systemPrompt,
        parentAgentId: def.parentAgentId,
        moduleId: def.moduleId,
        avatarColor: def.avatarColor,
        capabilities: def.capabilities,
        config: { escalationTriggers: def.escalationTriggers },
      },
    });
  }
}

// ============================================
// MEMORY OPERATIONS
// ============================================

export async function agentRemember(
  agentId: string,
  category: string,
  key: string,
  content: unknown,
  options: { confidence?: number; importance?: number; source?: string } = {}
) {
  return prisma.domainAgentMemory.upsert({
    where: { agentId_category_key: { agentId, category, key } },
    create: {
      agentId,
      category,
      key,
      content: content as any,
      confidence: options.confidence ?? 0.5,
      importance: options.importance ?? 0.5,
      source: options.source ?? 'system',
    },
    update: {
      content: content as any,
      confidence: options.confidence,
      importance: options.importance,
      accessCount: { increment: 1 },
    },
  });
}

export async function agentRecall(agentId: string, category?: string, limit = 20) {
  return prisma.domainAgentMemory.findMany({
    where: {
      agentId,
      ...(category ? { category } : {}),
    },
    orderBy: [{ importance: 'desc' }, { updatedAt: 'desc' }],
    take: limit,
  });
}

// ============================================
// INTER-AGENT MESSAGING
// ============================================

export async function sendAgentMessage(
  fromAgentId: string,
  toAgentId: string,
  type: 'escalation' | 'report' | 'query' | 'directive' | 'insight',
  subject: string,
  content: unknown,
  priority: 'low' | 'normal' | 'high' | 'urgent' = 'normal'
) {
  return prisma.domainAgentMessage.create({
    data: {
      fromAgentId,
      toAgentId,
      type,
      priority,
      subject,
      content: content as any,
      status: 'pending',
    },
  });
}

export async function getAgentInbox(agentId: string, status?: string) {
  return prisma.domainAgentMessage.findMany({
    where: {
      toAgentId: agentId,
      ...(status ? { status } : {}),
    },
    include: {
      fromAgent: { select: { agentId: true, name: true, title: true, avatarColor: true } },
    },
    orderBy: [{ priority: 'desc' }, { createdAt: 'desc' }],
    take: 50,
  });
}

// ============================================
// ESCALATION
// ============================================

export async function escalateToParent(
  agentId: string,
  subject: string,
  content: unknown,
  priority: 'high' | 'urgent' = 'high'
) {
  const agent = await prisma.domainAgent.findUnique({ where: { agentId } });
  if (!agent || !agent.parentAgentId) return null;

  const message = await sendAgentMessage(
    agentId,
    agent.parentAgentId,
    'escalation',
    subject,
    content,
    priority
  );

  // Record in memory
  await agentRemember(agentId, 'escalation_history', `escalation_${message.id}`, {
    subject,
    to: agent.parentAgentId,
    timestamp: new Date().toISOString(),
  }, { importance: 0.8, source: 'escalation' });

  return message;
}

// ============================================
// AGENT STATUS
// ============================================

export async function getAgentHierarchyStatus() {
  const agents = await prisma.domainAgent.findMany({
    orderBy: { domain: 'asc' },
    include: {
      _count: {
        select: {
          memories: true,
          sentMessages: true,
          receivedMessages: true,
        },
      },
    },
  });

  const pendingEscalations = await prisma.domainAgentMessage.count({
    where: { type: 'escalation', status: 'pending' },
  });

  return {
    agents: agents.map((a: any) => ({
      agentId: a.agentId,
      name: a.name,
      title: a.title,
      domain: a.domain,
      status: a.status,
      parentAgentId: a.parentAgentId,
      moduleId: a.moduleId,
      avatarColor: a.avatarColor,
      maturityLevel: a.maturityLevel,
      xp: a.xp,
      totalInteractions: a.totalInteractions,
      lastActiveAt: a.lastActiveAt,
      memoryCount: a._count.memories,
      messagesSent: a._count.sentMessages,
      messagesReceived: a._count.receivedMessages,
    })),
    pendingEscalations,
    totalAgents: agents.length,
    activeAgents: agents.filter((a: any) => a.status === 'active').length,
    dormantAgents: agents.filter((a: any) => a.status === 'dormant').length,
  };
}

/**
 * Record an interaction with an agent and update XP/maturity.
 */
export async function recordInteraction(agentId: string, xpGained = 5) {
  const agent = await prisma.domainAgent.update({
    where: { agentId },
    data: {
      totalInteractions: { increment: 1 },
      xp: { increment: xpGained },
      lastActiveAt: new Date(),
    },
  });

  // Check for maturity level up (every 100 XP)
  const newLevel = Math.min(5, Math.floor(agent.xp / 100));
  if (newLevel > agent.maturityLevel) {
    await prisma.domainAgent.update({
      where: { agentId },
      data: { maturityLevel: newLevel },
    });
  }

  return agent;
}
