import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import crypto from "crypto";
import { adminUnauthorizedResponse, isAdminRequestAuthorized } from "@/lib/admin-auth";

const AGENT_TYPES = ["BUILDER", "EVALUATOR", "JUDGE", "SCOUT"];
const SKILLS = ["React", "Node.js", "Python", "Rust", "Go", "Solidity", "DevOps", "AI", "Design"];

function randomChoice<T>(arr: T[]): T {
  return arr[Math.floor(Math.random() * arr.length)];
}

function randomSkills(count: number) {
  const shuffled = [...SKILLS].sort(() => 0.5 - Math.random());
  return shuffled.slice(0, count);
}

function isPrismaUniqueError(error: unknown) {
  return typeof error === "object" && error !== null && "code" in error && error.code === "P2002";
}

export async function POST(request: NextRequest) {
  if (!isAdminRequestAuthorized(request)) {
    return adminUnauthorizedResponse();
  }

  try {
    const logs: string[] = [];
    const log = (msg: string) => {
      console.log(msg);
      logs.push(msg);
    };

    log("🌊 The Great Swarm Commander API Initiated 🌊");

    // 1. Check if we have enough agents, if not create them
    const agentCount = await prisma.agentProfile.count();
    let agentIds: string[] = [];

    if (agentCount < 50) {
      log("[1/4] Generating 50 Agents...");
      for (let i = 0; i < 50; i++) {
        const id = `agent_sim_${crypto.randomBytes(4).toString("hex")}`;
        const type = randomChoice(AGENT_TYPES);
        const wallet = `0x${crypto.randomBytes(20).toString("hex")}`;
        await prisma.agentProfile.upsert({
          where: { agent_id: id },
          update: { status: "WHITELISTED" },
          create: {
            agent_id: id,
            type: type,
            status: "WHITELISTED",
            capabilities: randomSkills(3),
            discovery_source: "SIMULATION",
            wallet_address: wallet,
          }
        });
        agentIds.push(id);
      }
      log(`✅ 50 Agents generated.`);
    } else {
      const agents = await prisma.agentProfile.findMany({ select: { agent_id: true } });
      agentIds = agents.map(a => a.agent_id);
    }

    log(`\n--- Cycle Started ---`);
    
    // A. Create 1-3 new tasks
    const numTasks = Math.floor(Math.random() * 3) + 1;
    for (let i = 0; i < numTasks; i++) {
      const difficulty = randomChoice(["HELLO_WORLD", "COMPONENT", "VIEW", "EPIC"]);
      let reward = 0;
      if (difficulty === "HELLO_WORLD") reward = Math.floor(Math.random() * 100) + 50;
      if (difficulty === "COMPONENT") reward = Math.floor(Math.random() * 500) + 300;
      if (difficulty === "VIEW") reward = Math.floor(Math.random() * 1000) + 500;
      if (difficulty === "EPIC") reward = Math.floor(Math.random() * 10000) + 5000;

      const task = await prisma.task.create({
        data: {
          title: `[Sim] Auto-generated Task ${Date.now()}`,
          description: `This is an automated simulation task needing ${randomChoice(SKILLS)}.`,
          difficulty: difficulty,
          status: "OPEN",
          reward_amount: reward,
          reward_currency: "USDC",
          scope_clarity_score: 0.95,
          acceptance_criteria: {
            validation_mode: "VITEST_UNIT",
            test_file_content: "import { describe, it, expect } from 'vitest';\nit('simulation task placeholder', () => expect(true).toBe(true));",
            rules: [{ assertion: "simulation", expected: true, description: "Admin-only simulation task" }],
          },
          scout_id: randomChoice(agentIds),
        }
      });
      log(`[+] Task Created: ${task.id} (${difficulty} - $${reward})`);
    }

    // B. Find some OPEN tasks and add bids
    const openTasks = await prisma.task.findMany({ where: { status: "OPEN" }, take: 5 });
    for (const task of openTasks) {
      const builder = randomChoice(agentIds);
      const bidAmount = Math.floor(task.reward_amount * (Math.random() * 0.5 + 0.5));
      try {
        await prisma.bidProposal.create({
          data: {
            task_id: task.id,
            agent_id: builder,
            proposed_reward: bidAmount,
            estimated_duration_hours: Math.random() * 20 + 2,
            status: "PENDING",
            broker_agent_id: Math.random() > 0.7 ? randomChoice(agentIds) : null,
            broker_fee_percentage: Math.random() > 0.7 ? 5 : null,
          }
        });
        log(`  └─ Bid placed on ${task.id} by ${builder} for $${bidAmount}`);
      } catch (error) {
        if (isPrismaUniqueError(error)) {
          log(`  └─ Duplicate bid skipped on ${task.id} by ${builder}`);
          continue;
        }
        throw error;
      }
      
      // 50% chance to accept a bid and move to EXECUTING
      if (Math.random() > 0.5) {
        await prisma.task.update({
          where: { id: task.id },
          data: { status: "EXECUTING", builder_id: builder }
        });
        await prisma.bidProposal.updateMany({
          where: { task_id: task.id, agent_id: builder },
          data: { status: "ACCEPTED" }
        });
        log(`  └─ Task ${task.id} assigned to ${builder}!`);
      }
    }

    // C. Find some EXECUTING tasks and complete or dispute them
    const inProgressTasks = await prisma.task.findMany({ where: { status: "EXECUTING" }, take: 5 });
    for (const task of inProgressTasks) {
      if (Math.random() > 0.4) {
        // 60% chance to complete normally
        await prisma.task.update({
          where: { id: task.id },
          data: { status: "COMPLETED" }
        });
        log(`  [✓] Task ${task.id} completed successfully.`);
      } else {
        // 40% chance to DISPUTE
        await prisma.task.update({
          where: { id: task.id },
          data: { status: "DISPUTED" }
        });
        // Create an arbitration case
        const evaluator = randomChoice(agentIds);
        const arb = await prisma.arbitration.create({
          data: {
            task_id: task.id,
            status: "PENDING",
            builder_id: task.builder_id || randomChoice(agentIds),
            evaluator_id: evaluator,
          }
        });
        log(`  [!] DISPUTE RAISED on ${task.id}! Arbitration ${arb.id} started.`);
      }
    }

    // D. Resolve Arbitrations
    const arbitrations = await prisma.arbitration.findMany({ where: { status: "PENDING" }, take: 3 });
    for (const arb of arbitrations) {
      if (Math.random() > 0.5) {
        // Simulate a vote resolution
        const wonBy = Math.random() > 0.5 ? "BUILDER" : "EVALUATOR";
        await prisma.arbitration.update({
          where: { id: arb.id },
          data: {
            status: "RESOLVED",
            winning_party: wonBy,
          }
        });
        
        await prisma.task.update({
          where: { id: arb.task_id },
          data: { status: wonBy === "BUILDER" ? "COMPLETED" : "OPEN", builder_id: null }
        });
        log(`  [⚖] Arbitration ${arb.id} resolved in favor of ${wonBy}!`);
      }
    }

    log(`--- Cycle Complete ---`);

    return NextResponse.json({ success: true, logs });
  } catch (error: unknown) {
    console.error("[Simulate Error]", error);
    return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
  }
}
