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

import { serializeBuyer } from "@/features/buyers/lib/serialize-buyer";
import { buyerInputSchema } from "@/features/buyers/schemas/buyer.schema";
import { createAuditTrailSafe } from "@/lib/audit-trail";
import { buildAuditChangeMetadata } from "@/lib/audit-trail-diff";
import { requireApiAccess } from "@/lib/authorization";
import { resolveMasterCode } from "@/lib/master-code";
import { prisma } from "@/lib/prisma";

type RouteContext = {
  params: Promise<{
    id: string;
  }>;
};

function parseId(rawId: string) {
  try {
    return BigInt(rawId);
  } catch {
    return null;
  }
}

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

  const { id } = await context.params;
  const parsedId = parseId(id);

  if (parsedId === null) {
    return NextResponse.json({ message: "Invalid id" }, { status: 400 });
  }

  const buyer = await prisma.buyer.findUnique({
    where: { id: parsedId },
    include: {
      contactPeople: {
        orderBy: [{ createdAt: "asc" }, { id: "asc" }]
      }
    }
  });

  if (!buyer) {
    return NextResponse.json({ message: "Buyer not found" }, { status: 404 });
  }

  return NextResponse.json({
    data: serializeBuyer(buyer)
  });
}

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

  const { id } = await context.params;
  const parsedId = parseId(id);

  if (parsedId === null) {
    return NextResponse.json({ message: "Invalid id" }, { status: 400 });
  }

  const json = await request.json();
  const parsed = buyerInputSchema.safeParse(json);

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

  try {
    const existing = await prisma.buyer.findUnique({
      where: { id: parsedId },
      include: {
        contactPeople: {
          orderBy: [{ createdAt: "asc" }, { id: "asc" }]
        }
      }
    });

    if (!existing) {
      return NextResponse.json({ message: "Buyer not found" }, { status: 404 });
    }

    if (parsed.data.bank_name) {
      const bank = await prisma.bank.findFirst({
        where: {
          name: parsed.data.bank_name,
          status: "ACTIVE"
        }
      });

      if (!bank) {
        return NextResponse.json(
          {
            message: "Validasi gagal",
            errors: {
              bank_name: ["Bank harus dipilih dari master bank aktif untuk buyer"]
            }
          },
          { status: 400 }
        );
      }
    }

    const resolvedCode = await resolveMasterCode({
      role: auth.user.role,
      prefix: "CUS",
      requestedCode: parsed.data.code,
      existingCode: existing.code,
      countExisting: () =>
        prisma.buyer.count({ where: { code: { startsWith: "CUS" } } }),
      exists: async (code) =>
        (await prisma.buyer.count({
          where: {
            code,
            id: { not: parsedId }
          }
        })) > 0
    });

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

    const buyer = await prisma.buyer.update({
      where: { id: parsedId },
      data: {
        code: resolvedCode.code,
        name: parsed.data.name,
        phone: parsed.data.phone || null,
        email: parsed.data.email || null,
        bankName: parsed.data.bank_name || null,
        bankAccountNumber: parsed.data.bank_account_number || null,
        address: parsed.data.address || null,
        contactPeople: {
          deleteMany: {},
          create: parsed.data.contact_people.map((contactPerson) => ({
            name: contactPerson.name,
            mobilePhone: contactPerson.mobile_phone || null,
            email: contactPerson.email || null
          }))
        },
        status: parsed.data.status
      },
      include: {
        contactPeople: {
          orderBy: [{ createdAt: "asc" }, { id: "asc" }]
        }
      }
    });
    await createAuditTrailSafe({
      userId: auth.user.id,
      action: "CUSTOMER_UPDATED",
      entityType: "CUSTOMER",
      entityId: buyer.id,
      method: request.method,
      pathname: new URL(request.url).pathname,
      statusCode: 200,
      summary: `Buyer ${buyer.code} diubah`,
      metadata: buildAuditChangeMetadata(
        {
          code: existing.code,
          name: existing.name,
          phone: existing.phone,
          email: existing.email,
          bank_name: existing.bankName,
          bank_account_number: existing.bankAccountNumber,
          address: existing.address,
          contact_people: existing.contactPeople.map((contactPerson) => ({
            name: contactPerson.name,
            mobile_phone: contactPerson.mobilePhone,
            email: contactPerson.email
          })),
          status: existing.status
        },
        {
          code: buyer.code,
          name: buyer.name,
          phone: buyer.phone,
          email: buyer.email,
          bank_name: buyer.bankName,
          bank_account_number: buyer.bankAccountNumber,
          address: buyer.address,
          contact_people: buyer.contactPeople.map((contactPerson) => ({
            name: contactPerson.name,
            mobile_phone: contactPerson.mobilePhone,
            email: contactPerson.email
          })),
          status: buyer.status
        }
      )
    });

    return NextResponse.json({
      data: serializeBuyer(buyer)
    });
  } catch (error) {
    if (error instanceof PrismaClientKnownRequestError && error.code === "P2025") {
      return NextResponse.json({ message: "Buyer not found" }, { status: 404 });
    }

    if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") {
      return NextResponse.json(
        {
          message: "Validasi gagal",
          errors: {
            code: ["Kode pembeli sudah dipakai"]
          }
        },
        { status: 409 }
      );
    }

    throw error;
  }
}

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

  const { id } = await context.params;
  const parsedId = parseId(id);

  if (parsedId === null) {
    return NextResponse.json({ message: "Invalid id" }, { status: 400 });
  }

  try {
    const existing = await prisma.buyer.findUnique({ where: { id: parsedId } });
    await prisma.buyer.delete({
      where: { id: parsedId }
    });
    await createAuditTrailSafe({
      userId: auth.user.id,
      action: "CUSTOMER_DELETED",
      entityType: "CUSTOMER",
      entityId: parsedId,
      method: request.method,
      pathname: new URL(request.url).pathname,
      statusCode: 200,
      summary: `Buyer ${existing?.code ?? parsedId.toString()} dihapus`
    });

    return NextResponse.json({ success: true });
  } catch (error) {
    if (error instanceof PrismaClientKnownRequestError && error.code === "P2025") {
      return NextResponse.json({ message: "Buyer not found" }, { status: 404 });
    }

    throw error;
  }
}
