import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { logAuditEvent } from "@/lib/audit";
import { TaskStatus } from "@agent-bounty/contracts";

import { broadcastViaXMTP } from "@/lib/a2a-broadcasters/xmtp";
import { broadcastViaNostr } from "@/lib/a2a-broadcasters/nostr";
import { triggerWebhook } from "@/lib/a2a-broadcasters/webhook";
import { broadcastViaFarcaster } from "@/lib/a2a-broadcasters/farcaster";
import { broadcastViaMatrix } from "@/lib/a2a-broadcasters/matrix";
import { broadcastViaWaku } from "@/lib/a2a-broadcasters/waku";
import { broadcastViaTelegram } from "@/lib/a2a-broadcasters/telegram";
import { cronUnauthorizedResponse, isCronRequestAuthorized } from "@/lib/cron-auth";

export const dynamic = 'force-dynamic';

function getSemanticTags(capabilities: unknown) {
  if (typeof capabilities !== "object" || capabilities === null || Array.isArray(capabilities)) {
    return [];
  }

  const tags = (capabilities as { semantic_tags?: unknown }).semantic_tags;
  return Array.isArray(tags) ? tags.filter((tag): tag is string => typeof tag === "string") : [];
}

export async function GET(request: Request) {
  if (!isCronRequestAuthorized(request)) {
    return cronUnauthorizedResponse("A2A Dispatcher");
  }

  try {
    // 1. Find all OPEN tasks that have NOT been broadcasted via A2A
    const tasks = await prisma.task.findMany({
      where: {
        status: TaskStatus.OPEN,
      },
      include: {
        // We can't directly filter by absence of audit log easily in Prisma relation without a complex query,
        // so we just fetch them and filter in memory since OPEN tasks volume shouldn't be huge at any given second.
      }
    });

    // Get all A2A broadcast logs to filter out already-broadcasted tasks
    const broadcastLogs = await prisma.auditEvent.findMany({
      where: {
        action: "A2A_NETWORK_BROADCAST"
      },
      select: { entityId: true }
    });
    
    const broadcastedTaskIds = new Set(broadcastLogs.map(log => log.entityId));

    const tasksToBroadcast = tasks.filter(t => !broadcastedTaskIds.has(t.id));

    if (tasksToBroadcast.length === 0) {
      return NextResponse.json({ message: "No new tasks to broadcast.", count: 0 });
    }

    console.log(`[A2A Dispatcher] Found ${tasksToBroadcast.length} new tasks. Commencing pure A2A dispatch...`);

    const results = [];

    for (const task of tasksToBroadcast) {
      console.log(`\n===========================================`);
      console.log(`[A2A Dispatcher] Processing Task: ${task.title}`);

      // Phase 3.1 Smart Routing: Query for Agents with matching capabilities
      const requiredStack = task.required_stack || [];
      const matchingAgents = await prisma.agentProfile.findMany({
        where: {
          type: "BUILDER",
          status: "WHITELISTED"
        }
      });
      
      const targetWallets = matchingAgents
        .filter(agent => {
          const tags = getSemanticTags(agent.capabilities);
          return requiredStack.some((req: string) => tags.includes(req));
        })
        .map(agent => agent.wallet_address)
        .filter(Boolean) as string[];

      if (targetWallets.length > 0) {
        console.log(`[A2A Dispatcher] 🎯 Smart Routing: Found ${targetWallets.length} matching agents for tags ${requiredStack.join(', ')}`);
      } else {
        console.log(`[A2A Dispatcher] 🌐 No specific match, falling back to general broadcast.`);
      }

      // Timeout wrapper to ensure no broadcaster hangs the dispatcher
      const withTimeout = <T>(promise: Promise<T>, ms: number, name: string): Promise<T> => {
        return Promise.race([
          promise,
          new Promise<T>((_, reject) => 
            setTimeout(() => reject(new Error(`[${name}] Timeout after ${ms}ms`)), ms)
          )
        ]);
      };

      const TIMEOUT_MS = 5000;

      // Fire all broadcasters concurrently with 5-second timeout
      const [xmtpRes, nostrRes, webhookRes, farcasterRes, matrixRes, wakuRes, telegramRes] = await Promise.allSettled([
        withTimeout(broadcastViaXMTP({ ...task, target_wallets: targetWallets }), TIMEOUT_MS, 'XMTP'),
        withTimeout(broadcastViaNostr(task), TIMEOUT_MS, 'Nostr'),
        withTimeout(triggerWebhook(task.id, 'TASK_DISCOVERED', task), TIMEOUT_MS, 'Webhook'),
        withTimeout(broadcastViaFarcaster(task), TIMEOUT_MS, 'Farcaster'),
        withTimeout(broadcastViaMatrix(task), TIMEOUT_MS, 'Matrix'),
        withTimeout(broadcastViaWaku(task), TIMEOUT_MS, 'Waku'),
        withTimeout(broadcastViaTelegram(task), TIMEOUT_MS, 'Telegram')
      ]);

      // Log the event to prevent duplicate broadcasts
      await logAuditEvent(prisma, {
        actorType: "SYSTEM",
        actorId: "A2A_DISPATCHER",
        action: "A2A_NETWORK_BROADCAST",
        entityType: "TASK",
        entityId: task.id,
        reason: "Dispatched to Nostr, XMTP, Webhooks, Farcaster, Matrix, Waku, and Telegram",
        metadata: {
          xmtp: xmtpRes.status,
          nostr: nostrRes.status,
          webhook: webhookRes.status,
          farcaster: farcasterRes.status,
          matrix: matrixRes.status,
          waku: wakuRes.status,
          telegram: telegramRes.status
        }
      });

      results.push({
        task_id: task.id,
        status: "BROADCASTED"
      });
    }

    return NextResponse.json({ 
      message: "A2A Dispatch Complete", 
      broadcasted_count: results.length,
      results
    });

  } catch (error: unknown) {
    console.error("[A2A Dispatcher] Error:", error);
    return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
  }
}
