import { Prisma } from "@prisma/client";
import { prisma } from "./prisma";
import { MOVEMENT_TYPE, PRICE_TIER } from "./enums";
import { stockIn } from "./stock";

// Helper domain "Pusat (Kantor)": pengadaan (beli dari petani), stok pusat,
// distribusi ke cabang, dan aktivasi harga terjadwal. Semua mutasi stok lewat
// transaksi agar saldo pusat & cabang konsisten.

type Tx = Prisma.TransactionClient;

async function getOrCreateCentralStock(tx: Tx, productId: string) {
  const existing = await tx.centralStock.findUnique({ where: { productId } });
  if (existing) return existing;
  return tx.centralStock.create({ data: { productId } });
}

// Pembelian dari kandang/petani → stok pusat bertambah.
export async function procure(
  tx: Tx,
  opts: {
    supplierName: string;
    productId: string;
    quantity: number;
    pricePerUnit: number;
    notes?: string | null;
    userId: string;
  }
) {
  const cs = await getOrCreateCentralStock(tx, opts.productId);
  await tx.centralStock.update({
    where: { id: cs.id },
    data: { quantityAvailable: { increment: opts.quantity } },
  });
  return tx.procurement.create({
    data: {
      supplierName: opts.supplierName,
      productId: opts.productId,
      quantity: opts.quantity,
      pricePerUnit: opts.pricePerUnit,
      totalCost: Math.round(opts.quantity * opts.pricePerUnit),
      notes: opts.notes ?? null,
      createdBy: opts.userId,
    },
  });
}

// Distribusi stok pusat → cabang. Stok pusat berkurang, stok cabang bertambah
// (tercatat sebagai StockMovement type 'in' di cabang, sumber = Pusat).
export async function distribute(
  tx: Tx,
  opts: {
    branchId: string;
    productId: string;
    quantity: number;
    notes?: string | null;
    userId: string;
  }
) {
  const cs = await getOrCreateCentralStock(tx, opts.productId);
  if (cs.quantityAvailable < opts.quantity)
    throw new Error(
      `Stok pusat tidak cukup (tersedia ${cs.quantityAvailable}, diminta ${opts.quantity})`
    );
  await tx.centralStock.update({
    where: { id: cs.id },
    data: { quantityAvailable: { decrement: opts.quantity } },
  });
  await stockIn(
    tx,
    opts.branchId,
    opts.productId,
    opts.quantity,
    opts.userId,
    `Distribusi dari Pusat${opts.notes ? ` — ${opts.notes}` : ""}`
  );
  return tx.distribution.create({
    data: {
      branchId: opts.branchId,
      productId: opts.productId,
      quantity: opts.quantity,
      notes: opts.notes ?? null,
      createdBy: opts.userId,
    },
  });
}

// Aktivasi harga terjadwal yang tanggalnya sudah tiba (lazy activation).
// Dipanggil di awal endpoint harga/pemantauan. Idempotent: hanya memproses
// ScheduledPrice yang belum `appliedAt` dan effectiveDate <= sekarang.
export async function activateDuePrices(): Promise<number> {
  const now = new Date();
  const due = await prisma.scheduledPrice.findMany({
    where: { appliedAt: null, effectiveDate: { lte: now } },
    orderBy: { effectiveDate: "asc" },
  });
  if (due.length === 0) return 0;

  for (const sp of due) {
    await prisma.$transaction(async (tx: Tx) => {
      // Tutup harga global aktif produk ini, buat harga aktif baru.
      await tx.priceList.updateMany({
        where: {
          productId: sp.productId,
          tier: PRICE_TIER.OFFLINE,
          branchId: null,
          validTo: null,
        },
        data: { validTo: now },
      });
      await tx.priceList.create({
        data: {
          productId: sp.productId,
          price: sp.price,
          branchId: null,
          tier: PRICE_TIER.OFFLINE,
          setBy: sp.createdBy,
        },
      });
      await tx.scheduledPrice.update({
        where: { id: sp.id },
        data: { appliedAt: now },
      });
    });
  }
  return due.length;
}

// Awal & akhir "hari ini" dan "kemarin" (untuk perbandingan stok/omset harian).
export const MOVEMENT = MOVEMENT_TYPE;
