'use server';

import { redirect } from 'next/navigation';
import { prisma } from '@/lib/prisma';
import { applyStockMovement } from '@/lib/stock';
import { logFinancialChange } from '@/lib/financialAudit';

export type PurchaseItemInput = {
  productId: string | null; // null = loose material line (ink, packaging…)
  description: string;
  color: string | null;
  size: string | null;
  quantity: number;
  unitCost: number; // pence
};

const MAX_INVOICE_BYTES = 8 * 1024 * 1024; // keep data-URL rows sane

export async function createPurchase(formData: FormData) {
  const supplierName = String(formData.get('supplierName') ?? '').trim();
  const purchasedAtInput = String(formData.get('purchasedAt') ?? '').trim();
  const notes = String(formData.get('notes') ?? '').trim();
  const itemsJson = String(formData.get('items') ?? '[]');
  const invoice = formData.get('invoice') as File | null;

  if (!supplierName) throw new Error('Supplier name is required.');

  let items: PurchaseItemInput[];
  try {
    items = JSON.parse(itemsJson);
  } catch {
    throw new Error('Could not read the purchase items.');
  }
  items = items.filter((i) => i.description.trim() && i.quantity > 0);
  if (items.length === 0) throw new Error('A purchase needs at least one item.');
  for (const item of items) {
    if (!Number.isInteger(item.quantity) || item.quantity < 1 || item.quantity > 100000) {
      throw new Error('Quantities must be whole numbers.');
    }
    if (!Number.isInteger(item.unitCost) || item.unitCost < 0) {
      throw new Error('Costs cannot be negative.');
    }
  }

  let invoiceDataUrl: string | null = null;
  let invoiceFileName: string | null = null;
  if (invoice && invoice.size > 0) {
    if (invoice.size > MAX_INVOICE_BYTES) {
      throw new Error('Invoice file is too large — keep it under 8 MB.');
    }
    const bytes = Buffer.from(await invoice.arrayBuffer());
    const mimeType = invoice.type || 'application/octet-stream';
    invoiceDataUrl = `data:${mimeType};base64,${bytes.toString('base64')}`;
    invoiceFileName = invoice.name || 'invoice';
  }

  const total = items.reduce((sum, i) => sum + i.quantity * i.unitCost, 0);

  const purchaseDate = purchasedAtInput ? new Date(purchasedAtInput) : new Date();

  const purchase = await prisma.purchase.create({
    data: {
      supplierName,
      purchasedAt: purchaseDate,
      invoiceDataUrl,
      invoiceFileName,
      total,
      notes: notes || null,
      items: {
        create: items.map((i) => ({
          productId: i.productId,
          description: i.description.trim(),
          color: i.color,
          size: i.size,
          quantity: i.quantity,
          unitCost: i.unitCost,
        })),
      },
      // Auto-create an Expense entry for accounting — every purchase is an expense.
      expense: {
        create: {
          date: purchaseDate,
          description: `Stock purchase: ${supplierName}`,
          category: 'Stock purchases',
          amount: total,
          notes: notes || null,
        },
      },
    },
  });

  // Log the purchase creation
  await logFinancialChange(
    'CREATE',
    'PURCHASE',
    purchase.id,
    {
      supplier: { old: null, new: supplierName },
      total: { old: 0, new: total },
      items: { old: 0, new: items.length },
    },
    total,
    'New purchase recorded'
  );

  // Product lines add to stock; material lines are just logged.
  await applyStockMovement(items, 1);

  redirect('/admin/accounts/purchases');
}

export async function deletePurchase(formData: FormData) {
  const id = String(formData.get('id') ?? '');
  if (!id) return;
  const purchase = await prisma.purchase.findUnique({ where: { id }, include: { items: true } });
  if (!purchase) return;

  // Log the deletion before deleting
  await logFinancialChange(
    'DELETE',
    'PURCHASE',
    id,
    {
      supplier: { old: purchase.supplierName, new: null },
      total: { old: purchase.total, new: 0 },
      items: { old: purchase.items.length, new: 0 },
    },
    purchase.total,
    'Purchase deleted'
  );

  await prisma.purchase.delete({ where: { id } });
  // Removing a purchase takes its stock back out.
  await applyStockMovement(purchase.items, -1);
  redirect('/admin/accounts/purchases');
}

// Direct correction from the stock page — "I counted the shelf and there are
// actually N". Sets the absolute value rather than nudging by a delta.
export async function setStockQuantity(formData: FormData) {
  const productId = String(formData.get('productId') ?? '');
  const color = String(formData.get('color') ?? '');
  const size = String(formData.get('size') ?? '');
  const quantity = Math.trunc(Number(formData.get('quantity')));
  if (!productId || !color || !Number.isFinite(quantity)) return;

  await prisma.stockLevel.upsert({
    where: { productId_color_size: { productId, color, size } },
    create: { productId, color, size, quantity },
    update: { quantity },
  });
  redirect('/admin/accounts/stock');
}
