import { eq, and, desc, gte, sql } from 'drizzle-orm';
import { db } from '../db/index';
import { agents, auditLog } from '../db/schema';
import { eventBus } from '../events/bus';

// ═══════════════════════════════════════════════════════════
// Agent Service — Health monitoring, heartbeat tracking
// ═══════════════════════════════════════════════════════════

export async function listAgents() {
  const items = await db.select().from(agents).orderBy(desc(agents.updatedAt));

  // Enrich with computed health status
  const now = Date.now();
  return items.map((agent) => ({
    ...agent,
    health: computeHealth(agent, now),
  }));
}

export async function getAgent(id: string) {
  const results = await db.select().from(agents).where(eq(agents.id, id)).limit(1);
  const agent = results[0];

  if (!agent) return null;

  const now = Date.now();
  return {
    ...agent,
    health: computeHealth(agent, now),
  };
}

export async function heartbeat(
  agentId: string,
  data: {
    status: string;
    metrics?: Record<string, number>;
    currentTaskId?: string | null;
    currentPipelineId?: string | null;
  }
) {
  const existing = await db.query.agents.findFirst({
    where: eq(agents.id, agentId),
  });

  if (!existing) return null;

  const previousStatus = existing.status;
  const now = new Date();

  // Calculate uptime from first heartbeat or creation
  const createdMs = existing.createdAt.getTime();
  const uptimeSeconds = Math.floor((now.getTime() - createdMs) / 1000);

  const [updated] = await db
    .update(agents)
    .set({
      status: data.status,
      lastHeartbeat: now,
      uptimeSeconds,
      currentTaskId: data.currentTaskId !== undefined ? data.currentTaskId : existing.currentTaskId,
      currentPipelineId: data.currentPipelineId !== undefined ? data.currentPipelineId : existing.currentPipelineId,
      updatedAt: now,
    })
    .where(eq(agents.id, agentId))
    .returning();

  // Emit heartbeat event
  await eventBus.emit({
    type: 'agent.heartbeat',
    timestamp: now.toISOString(),
    data: {
      agentId,
      agentName: existing.name,
      status: data.status,
      health: computeHealth(updated, now.getTime()),
      metrics: data.metrics || {},
    },
    actor: { type: 'agent', id: agentId },
  });

  // Emit status change if changed
  if (previousStatus !== data.status) {
    await eventBus.emit({
      type: 'agent.status_changed',
      timestamp: now.toISOString(),
      data: {
        agentId,
        agentName: existing.name,
        fromStatus: previousStatus,
        toStatus: data.status,
        currentTaskId: updated.currentTaskId,
      },
      actor: { type: 'agent', id: agentId },
    });
  }

  return updated;
}

export async function getAgentActivity(
  agentId: string,
  opts: { since?: string; limit?: number }
) {
  const { limit = 50 } = opts;

  const conditions = [
    eq(auditLog.actorId, agentId),
  ];

  if (opts.since) {
    conditions.push(gte(auditLog.createdAt, new Date(opts.since)));
  }

  const items = await db
    .select()
    .from(auditLog)
    .where(and(...conditions))
    .orderBy(desc(auditLog.createdAt))
    .limit(limit);

  return items;
}

// ─── Health Computation ─────────────────────────────────

function computeHealth(
  agent: {
    lastHeartbeat: Date | null;
    uptimeSeconds: number | null;
    errorCount24h: number | null;
    tasksCompletedTotal: number | null;
  },
  nowMs: number
) {
  const lastHb = agent.lastHeartbeat ? agent.lastHeartbeat.getTime() : 0;
  const secondsSinceHeartbeat = lastHb ? Math.floor((nowMs - lastHb) / 1000) : Infinity;

  // Tasks completed in 24h (approximation — would use a rolling counter in prod)
  const tasksCompleted24h = 0; // Would track separately in production
  const errorRate = agent.errorCount24h
    ? agent.errorCount24h / Math.max(agent.tasksCompletedTotal || 1, 1)
    : 0;

  return {
    uptimeSeconds: agent.uptimeSeconds || 0,
    tasksCompleted24h,
    errorRate: Math.min(errorRate, 1),
    lastHeartbeat: agent.lastHeartbeat?.toISOString() || null,
    secondsSinceHeartbeat,
    isHealthy: secondsSinceHeartbeat < 120, // 2 min threshold
  };
}
