import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
import { NextResponse } from "next/server";

import {
  AGENT_BALANCE_DIRECTIONS,
  AGENT_BALANCE_SOURCES,
  AGENT_BALANCE_TYPES,
  createAgentBalanceMutation
} from "@/features/agents/lib/balance-mutations";
import { serializeAgent } from "@/features/agents/lib/serialize-agent";
import { agentInputSchema } from "@/features/agents/schemas/agent.schema";
import { createAuditTrailSafe } from "@/lib/audit-trail";
import { resolveMasterCode } from "@/lib/master-code";
import { prisma } from "@/lib/prisma";
import { requireApiAccess } from "@/lib/authorization";

export async function GET(request: Request) {
  const auth = requireApiAccess(request);
  if (!auth.ok) return auth.response;

  const data = await prisma.agent.findMany({
    include: {
      profitShareScheme: true,
      bankAccounts: {
        include: {
          bank: true
        }
      }
    },
    orderBy: [{ createdAt: "desc" }]
  });

  return NextResponse.json({ data: data.map(serializeAgent) });
}

export async function POST(request: Request) {
  const auth = requireApiAccess(request);
  if (!auth.ok) return auth.response;

  const parsed = agentInputSchema.safeParse(await request.json());
  if (!parsed.success) {
    return NextResponse.json(
      { message: "Validasi gagal", errors: parsed.error.flatten().fieldErrors },
      { status: 400 }
    );
  }

  try {
    const profitShareSchemeId = BigInt(parsed.data.profit_share_scheme_id);
    const bankIds = parsed.data.bank_accounts.map((account) => BigInt(account.bank_id));

    const [scheme, banks] = await Promise.all([
      prisma.profitShareScheme.findFirst({
        where: { id: profitShareSchemeId, status: "ACTIVE" }
      }),
      prisma.bank.findMany({
        where: { id: { in: bankIds }, status: "ACTIVE" }
      })
    ]);

    if (!scheme) {
      return NextResponse.json(
        { message: "Validasi gagal", errors: { profit_share_scheme_id: ["Skema bagi hasil harus dipilih dari master aktif"] } },
        { status: 400 }
      );
    }

    if (banks.length !== bankIds.length) {
      return NextResponse.json(
        { message: "Validasi gagal", errors: { bank_accounts: ["Semua rekening harus memilih bank aktif dari master"] } },
        { status: 400 }
      );
    }

    const resolvedCode = await resolveMasterCode({
      role: auth.user.role,
      prefix: "AGT",
      requestedCode: parsed.data.code,
      countExisting: () => prisma.agent.count({ where: { code: { startsWith: "AGT" } } }),
      exists: async (code) => (await prisma.agent.count({ where: { code } })) > 0
    });

    if (!resolvedCode.ok) {
      return NextResponse.json(
        { message: "Validasi gagal", errors: { code: [resolvedCode.message] } },
        { status: 400 }
      );
    }

    const joinDate = new Date(parsed.data.join_date);
    const agent = await prisma.$transaction(async (tx) => {
      const created = await tx.agent.create({
        data: {
          code: resolvedCode.code,
          name: parsed.data.name,
          identityType: parsed.data.identity_type,
          identityNumber: parsed.data.identity_number,
          mobilePhone: parsed.data.mobile_phone || null,
          email: parsed.data.email || null,
          address: parsed.data.address || null,
          notes: parsed.data.notes || null,
          joinDate,
          profitShareSchemeId,
          currentBalance: parsed.data.profit_share_balance,
          capitalBalance: parsed.data.capital_balance,
          bankAccounts: {
            create: parsed.data.bank_accounts.map((account) => ({
              bankId: BigInt(account.bank_id),
              accountNumber: account.account_number
            }))
          }
        },
        include: {
          profitShareScheme: true,
          bankAccounts: { include: { bank: true } }
        }
      });

      if (parsed.data.profit_share_balance > 0) {
        await createAgentBalanceMutation(tx, {
          agentId: created.id,
          balanceType: AGENT_BALANCE_TYPES.PROFIT_SHARE,
          direction: AGENT_BALANCE_DIRECTIONS.IN,
          source: AGENT_BALANCE_SOURCES.OPENING_BALANCE,
          amount: parsed.data.profit_share_balance,
          balanceAfter: parsed.data.profit_share_balance,
          effectiveDate: joinDate,
          notes: "Saldo bagi hasil awal agent"
        });
      }

      if (parsed.data.capital_balance > 0) {
        await createAgentBalanceMutation(tx, {
          agentId: created.id,
          balanceType: AGENT_BALANCE_TYPES.CAPITAL,
          direction: AGENT_BALANCE_DIRECTIONS.IN,
          source: AGENT_BALANCE_SOURCES.OPENING_BALANCE,
          amount: parsed.data.capital_balance,
          balanceAfter: parsed.data.capital_balance,
          effectiveDate: joinDate,
          notes: "Saldo modal awal agent"
        });
      }

      return created;
    });

    await createAuditTrailSafe({
      userId: auth.user.id,
      action: "AGENT_CREATED",
      entityType: "AGENT",
      entityId: agent.id,
      method: request.method,
      pathname: new URL(request.url).pathname,
      statusCode: 201,
      summary: `Agent ${agent.code} dibuat`
    });

    return NextResponse.json({ data: serializeAgent(agent) }, { status: 201 });
  } catch (error) {
    if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") {
      return NextResponse.json(
        { message: "Validasi gagal", errors: { identity_number: ["Kode agen atau identitas sudah dipakai"] } },
        { status: 409 }
      );
    }
    throw error;
  }
}
