import { NextResponse } from "next/server";

import {
  purchaseAnalysisInputSchema,
  type PurchaseAnalysisInput
} from "@/features/purchase-analysis/schemas/purchase-analysis.schema";
import { serializePurchaseAnalysisDetail } from "@/features/purchase-analysis/lib/serialize-purchase-analysis";
import { createAuditTrailSafe } from "@/lib/audit-trail";
import { buildAuditChangeMetadata } from "@/lib/audit-trail-diff";
import { requireApiAccess } from "@/lib/authorization";
import { prisma } from "@/lib/prisma";

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

const analysisInclude = {
  agent: {
    select: {
      id: true,
      name: true
    }
  },
  profitShareScheme: {
    select: {
      shareAgent: true
    }
  },
  lines: {
    select: {
      subtotal: true,
      qtyOrdered: true,
      qtyReceived: true,
      qtyAccepted: true,
      unitPrice: true,
      malUnitPrice: true,
      moistureReceivedPercent: true,
      purchaseMoisturePercent: true,
      marketReferencePrice: true,
      unit: {
        select: {
          code: true
        }
      }
    }
  },
  lots: {
    select: {
      originalQty: true,
      finalMoisturePercent: true,
      aboveAverageRatioPercent: true,
      unit: {
        select: {
          code: true
        }
      }
    }
  },
  analysis: {
    include: {
      costEntries: true
    }
  }
} as const;

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

function toDecimal(value: number | null | undefined) {
  if (value === undefined || value === null) return null;
  return value;
}

async function upsertAnalysis(purchaseId: bigint, payload: PurchaseAnalysisInput) {
  return prisma.purchaseAnalysis.upsert({
    where: { purchaseId },
    update: {
      status: payload.status,
      weightBuy: toDecimal(payload.weight_buy),
      weightReceived: toDecimal(payload.weight_received),
      weightFinal: toDecimal(payload.weight_final),
      moistureBuyPercent: toDecimal(payload.moisture_buy_percent),
      moistureReceivedPercent: toDecimal(payload.moisture_received_percent),
      moistureFinalPercent: toDecimal(payload.moisture_final_percent),
      aboveAverageRatioPercent: toDecimal(payload.above_average_ratio_percent),
      averagePrice: toDecimal(payload.average_price),
      modalBeli: toDecimal(payload.modal_beli),
      modalMasuk: toDecimal(payload.modal_masuk),
      modalJual: toDecimal(payload.modal_jual),
      modalBarang: toDecimal(payload.modal_barang),
      totalModalBeli: toDecimal(payload.total_modal_beli),
      totalModalMal: toDecimal(payload.total_modal_mal),
      marketReferencePrice: toDecimal(payload.market_reference_price),
      marketValuationTotal: toDecimal(payload.market_valuation_total),
      agentProfitShareTotal: payload.agent_profit_share_total,
      notes: payload.notes || null,
      costEntries: {
        deleteMany: {},
        create: payload.cost_entries.map((entry) => ({
          costType: entry.cost_type,
          description: entry.description || null,
          amount: entry.amount
        }))
      }
    },
    create: {
      purchaseId,
      status: payload.status,
      weightBuy: toDecimal(payload.weight_buy),
      weightReceived: toDecimal(payload.weight_received),
      weightFinal: toDecimal(payload.weight_final),
      moistureBuyPercent: toDecimal(payload.moisture_buy_percent),
      moistureReceivedPercent: toDecimal(payload.moisture_received_percent),
      moistureFinalPercent: toDecimal(payload.moisture_final_percent),
      aboveAverageRatioPercent: toDecimal(payload.above_average_ratio_percent),
      averagePrice: toDecimal(payload.average_price),
      modalBeli: toDecimal(payload.modal_beli),
      modalMasuk: toDecimal(payload.modal_masuk),
      modalJual: toDecimal(payload.modal_jual),
      modalBarang: toDecimal(payload.modal_barang),
      totalModalBeli: toDecimal(payload.total_modal_beli),
      totalModalMal: toDecimal(payload.total_modal_mal),
      marketReferencePrice: toDecimal(payload.market_reference_price),
      marketValuationTotal: toDecimal(payload.market_valuation_total),
      agentProfitShareTotal: payload.agent_profit_share_total,
      notes: payload.notes || null,
      costEntries: {
        create: payload.cost_entries.map((entry) => ({
          costType: entry.cost_type,
          description: entry.description || null,
          amount: entry.amount
        }))
      }
    }
  });
}

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

  const parsedId = parseId((await context.params).purchaseId);
  if (parsedId === null) {
    return NextResponse.json({ message: "Invalid purchase id" }, { status: 400 });
  }

  try {
    const purchase = await prisma.purchase.findUnique({
      where: { id: parsedId },
      select: {
        id: true,
        purchaseNo: true,
        purchaseDate: true,
        status: true,
        moistureBuyPercent: true,
        moistureReceivedPercent: true,
        aboveAverageRatioPercent: true,
        mkSharePercent: true,
        nonMkSharePercent: true,
        shippingCost: true,
        incomingOperationalCost: true,
        afterArrivalOperationalCost: true,
        agent: analysisInclude.agent,
        profitShareScheme: analysisInclude.profitShareScheme,
        lines: analysisInclude.lines,
        lots: analysisInclude.lots,
        analysis: analysisInclude.analysis
      }
    });

    if (!purchase) {
      return NextResponse.json({ message: "Purchase not found" }, { status: 404 });
    }
    if (purchase.status !== "SUBMITTED") {
      return NextResponse.json(
        { message: "Purchase analysis hanya tersedia untuk purchase final" },
        { status: 404 }
      );
    }

    return NextResponse.json({
      data: serializePurchaseAnalysisDetail(purchase)
    });
  } catch (error) {
    console.error(`Failed to load purchase analysis detail for ${parsedId.toString()}:`, error);
    return NextResponse.json(
      { message: "Gagal memuat detail analisis pembelian" },
      { status: 500 }
    );
  }
}

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

  const parsedId = parseId((await context.params).purchaseId);
  if (parsedId === null) {
    return NextResponse.json({ message: "Invalid purchase id" }, { status: 400 });
  }

  let requestPayload: unknown;
  try {
    requestPayload = await request.json();
  } catch {
    return NextResponse.json({ message: "Invalid request body" }, { status: 400 });
  }

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

  try {
    const purchase = await prisma.purchase.findUnique({
      where: { id: parsedId },
      select: { id: true }
    });
    if (!purchase) {
      return NextResponse.json({ message: "Purchase not found" }, { status: 404 });
    }

    const existingAnalysis = await prisma.purchaseAnalysis.findUnique({
      where: { purchaseId: parsedId },
      include: { costEntries: true }
    });

    await upsertAnalysis(parsedId, parsed.data);

    const refreshed = await prisma.purchase.findUnique({
      where: { id: parsedId },
      select: {
        id: true,
        purchaseNo: true,
        purchaseDate: true,
        status: true,
        moistureBuyPercent: true,
        moistureReceivedPercent: true,
        aboveAverageRatioPercent: true,
        mkSharePercent: true,
        nonMkSharePercent: true,
        shippingCost: true,
        incomingOperationalCost: true,
        afterArrivalOperationalCost: true,
        agent: analysisInclude.agent,
        profitShareScheme: analysisInclude.profitShareScheme,
        lines: analysisInclude.lines,
        lots: analysisInclude.lots,
        analysis: analysisInclude.analysis
      }
    });

    if (!refreshed) {
      return NextResponse.json({ message: "Purchase not found" }, { status: 404 });
    }
    if (refreshed.status !== "SUBMITTED") {
      return NextResponse.json(
        { message: "Purchase analysis hanya tersedia untuk purchase final" },
        { status: 404 }
      );
    }

    await createAuditTrailSafe({
      userId: auth.user.id,
      action: "PURCHASE_ANALYSIS_SAVED",
      entityType: "PURCHASE_ANALYSIS",
      entityId: parsedId,
      method: request.method,
      pathname: new URL(request.url).pathname,
      statusCode: 200,
      summary: `Purchase analysis untuk purchase ${parsedId.toString()} disimpan`,
      metadata: buildAuditChangeMetadata(
        {
          status: existingAnalysis?.status ?? null,
          weight_buy: existingAnalysis?.weightBuy?.toNumber() ?? null,
          weight_received: existingAnalysis?.weightReceived?.toNumber() ?? null,
          weight_final: existingAnalysis?.weightFinal?.toNumber() ?? null,
          moisture_buy_percent: existingAnalysis?.moistureBuyPercent?.toNumber() ?? null,
          moisture_received_percent: existingAnalysis?.moistureReceivedPercent?.toNumber() ?? null,
          moisture_final_percent: existingAnalysis?.moistureFinalPercent?.toNumber() ?? null,
          above_average_ratio_percent: existingAnalysis?.aboveAverageRatioPercent?.toNumber() ?? null,
          average_price: existingAnalysis?.averagePrice?.toNumber() ?? null,
          modal_beli: existingAnalysis?.modalBeli?.toNumber() ?? null,
          modal_masuk: existingAnalysis?.modalMasuk?.toNumber() ?? null,
          modal_jual: existingAnalysis?.modalJual?.toNumber() ?? null,
          modal_barang: existingAnalysis?.modalBarang?.toNumber() ?? null,
          total_modal_beli: existingAnalysis?.totalModalBeli?.toNumber() ?? null,
          total_modal_mal: existingAnalysis?.totalModalMal?.toNumber() ?? null,
          market_reference_price: existingAnalysis?.marketReferencePrice?.toNumber() ?? null,
          market_valuation_total: existingAnalysis?.marketValuationTotal?.toNumber() ?? null,
          agent_profit_share_total: existingAnalysis?.agentProfitShareTotal?.toNumber() ?? null,
          notes: existingAnalysis?.notes ?? null,
          cost_entries: (existingAnalysis?.costEntries ?? []).map((entry) => ({
            cost_type: entry.costType,
            description: entry.description,
            amount: entry.amount.toNumber()
          }))
        },
        {
          status: parsed.data.status,
          weight_buy: parsed.data.weight_buy,
          weight_received: parsed.data.weight_received,
          weight_final: parsed.data.weight_final,
          moisture_buy_percent: parsed.data.moisture_buy_percent,
          moisture_received_percent: parsed.data.moisture_received_percent,
          moisture_final_percent: parsed.data.moisture_final_percent,
          above_average_ratio_percent: parsed.data.above_average_ratio_percent,
          average_price: parsed.data.average_price,
          modal_beli: parsed.data.modal_beli,
          modal_masuk: parsed.data.modal_masuk,
          modal_jual: parsed.data.modal_jual,
          modal_barang: parsed.data.modal_barang,
          total_modal_beli: parsed.data.total_modal_beli,
          total_modal_mal: parsed.data.total_modal_mal,
          market_reference_price: parsed.data.market_reference_price,
          market_valuation_total: parsed.data.market_valuation_total,
          agent_profit_share_total: parsed.data.agent_profit_share_total,
          notes: parsed.data.notes || null,
          cost_entries: parsed.data.cost_entries
        }
      )
    });

    return NextResponse.json({
      data: serializePurchaseAnalysisDetail(refreshed)
    });
  } catch (error) {
    console.error(`Failed to save purchase analysis for ${parsedId.toString()}:`, error);
    return NextResponse.json(
      { message: "Gagal menyimpan analisis pembelian" },
      { status: 500 }
    );
  }
}
