import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { z } from "zod";

const PUBLIC_MCP_BETA_TOKEN = (process.env.PUBLIC_MCP_BETA_TOKEN || "").trim();
const A2A_RPC_ALLOW_TASK_CREATE = process.env.A2A_RPC_ALLOW_TASK_CREATE === "true";

const JsonRpcRequestSchema = z.object({
  jsonrpc: z.literal("2.0"),
  method: z.string().min(1),
  params: z.unknown().optional(),
  id: z.union([z.string(), z.number()]).optional()
});

const SubmitBidParamsSchema = z.object({
  task_id: z.string().uuid(),
  agent_id: z.string().min(1).max(120),
  developer_wallet: z
    .string()
    .regex(/^(0x[a-fA-F0-9]{40}|acct_[a-zA-Z0-9]+)$/)
    .optional(),
  proposed_reward: z.number().int().positive().max(1_000_000_00),
  estimated_duration_hours: z.number().positive().max(24 * 30),
  quality_guarantee: z.string().max(1000).optional(),
  broker_agent_id: z.string().max(120).optional(),
  broker_fee_percentage: z.number().min(0).max(100).optional()
});

const ProposeBountyParamsSchema = z.object({
  title: z.string().min(5).max(120),
  description: z.string().min(20).max(2000),
  budget_cents: z.number().int().positive().max(1_000_000_00),
  origin_agent_id: z.string().min(1).max(120),
  required_capabilities: z.array(z.string().min(1).max(50)).max(20).optional()
});

function isAuthorizedA2aRequest(request: NextRequest) {
  const authHeader = request.headers.get("Authorization");
  if (!authHeader?.startsWith("Bearer ")) {
    return false;
  }

  const token = authHeader.slice("Bearer ".length);
  return Boolean(process.env.API_KEY && token === process.env.API_KEY) ||
    Boolean(PUBLIC_MCP_BETA_TOKEN && token === PUBLIC_MCP_BETA_TOKEN);
}

function rpcError(id: string | number | undefined, code: number, message: string, status: number) {
  return NextResponse.json({
    jsonrpc: "2.0",
    error: { code, message },
    id
  }, { status });
}

export async function POST(request: NextRequest) {
  let rpcId: string | number | undefined;

  if (!isAuthorizedA2aRequest(request)) {
    return rpcError(undefined, -32001, "Unauthorized", 401);
  }

  try {
    const body = await request.json();
    const parsed = JsonRpcRequestSchema.parse(body);
    rpcId = parsed.id;

    if (parsed.method === "a2a_submit_bid") {
      const params = SubmitBidParamsSchema.parse(parsed.params);
      const agent = await prisma.agentProfile.findUnique({
        where: { agent_id: params.agent_id }
      });

      if (!agent || agent.status !== "WHITELISTED") {
        return rpcError(rpcId, -32003, "Agent is not whitelisted", 403);
      }

      let validAgent = agent;
      if (params.developer_wallet && !agent.wallet_address) {
        validAgent = await prisma.agentProfile.update({
          where: { agent_id: params.agent_id },
          data: { wallet_address: params.developer_wallet },
        });
      } else if (params.developer_wallet && agent.wallet_address !== params.developer_wallet) {
        return rpcError(rpcId, -32003, "developer_wallet does not match registered agent wallet", 403);
      }

      const result = await prisma.$transaction(async (tx) => {
        const task = await tx.task.findUnique({ where: { id: params.task_id } });
        if (!task || task.status !== "OPEN") {
          throw new Error("Task is not OPEN or does not exist");
        }

        if (task.difficulty === "EPIC" && validAgent.tier !== "PREMIUM") {
          throw new Error("EPIC difficulty tasks require the PREMIUM tier.");
        }

        const newBid = await tx.bidProposal.create({
          data: {
            task_id: params.task_id,
            agent_id: validAgent.agent_id,
            proposed_reward: params.proposed_reward,
            estimated_duration_hours: params.estimated_duration_hours,
            quality_guarantee: params.quality_guarantee,
            broker_agent_id: params.broker_agent_id,
            broker_fee_percentage: params.broker_fee_percentage,
            status: "PENDING"
          }
        });
        return newBid;
      });

      return NextResponse.json({
        jsonrpc: "2.0",
        result: {
          bid_id: result.id,
          task_id: result.task_id,
          status: result.status,
          proposed_reward: result.proposed_reward
        },
        id: rpcId
      });
    }

    if (parsed.method === "a2a_propose_bounty") {
      if (!A2A_RPC_ALLOW_TASK_CREATE) {
        return rpcError(rpcId, -32003, "A2A task creation is disabled", 403);
      }

      const params = ProposeBountyParamsSchema.parse(parsed.params);
      const newTask = await prisma.task.create({
        data: {
          title: `[EXTERNAL] ${params.title}`,
          description: `Bounty proposed by external agent ${params.origin_agent_id}.\n\n${params.description}`,
          reward_amount: params.budget_cents,
          reward_currency: "USDC",
          status: "DRAFT",
          difficulty: "HELLO_WORLD",
          created_by_agent: params.origin_agent_id,
          scope_clarity_score: 0.9,
          required_stack: params.required_capabilities || ["TypeScript"],
          acceptance_criteria: {
            validation_mode: "VITEST_UNIT",
            test_file_content: "import { describe, it, expect } from 'vitest';\nit('external bounty requires explicit platform review', () => expect(true).toBe(true));",
            rules: [
              {
                assertion: "platform_review_required",
                expected: true,
                description: "External A2A bounty proposals are stored as drafts until reviewed.",
              },
            ],
          }
        }
      });

      return NextResponse.json({
        jsonrpc: "2.0",
        result: {
          assigned_task_id: newTask.id,
          status: newTask.status,
          message: "Bounty draft registered for platform review."
        },
        id: rpcId
      });
    }

    return rpcError(rpcId, -32601, "Method not found", 404);
  } catch (error: unknown) {
    console.error("[a2a_rpc] Error:", error);

    if (error instanceof z.ZodError) {
      return rpcError(rpcId, -32602, "Invalid params", 400);
    }

    if (
      typeof error === "object" &&
      error !== null &&
      "code" in error &&
      (error as { code?: unknown }).code === "P2002"
    ) {
      return rpcError(rpcId, -32009, "Agent has already submitted a bid for this task", 409);
    }

    return rpcError(rpcId, -32000, error instanceof Error ? error.message : "Server error", 400);
  }
}
