import { Product, StockMovement } from '../Features/products/schema/product.schema';

export type LineItemInput = {
  type: 'SERVICE' | 'PRODUCT';
  refId?: string | null;
  name: string;
  quantity?: number;
  unitPrice?: number;
};

export type NormalizedLineItem = {
  type: 'SERVICE' | 'PRODUCT';
  refId: string | null;
  name: string;
  quantity: number;
  unitPrice: number;
  subtotal: number;
};

export function normalizeLineItems(items: LineItemInput[] = []): NormalizedLineItem[] {
  return items
    .filter((item) => item?.name?.trim())
    .map((item) => {
      const quantity = Math.max(Number(item.quantity) || 1, 1);
      const unitPrice = Math.max(Number(item.unitPrice) || 0, 0);
      return {
        type: item.type === 'PRODUCT' ? 'PRODUCT' : 'SERVICE',
        refId: item.refId ? String(item.refId) : null,
        name: String(item.name).trim(),
        quantity,
        unitPrice,
        subtotal: quantity * unitPrice,
      };
    });
}

export function buildServiceSummary(lineItems: NormalizedLineItem[], fallback = 'Custom appointment') {
  const services = lineItems.filter((item) => item.type === 'SERVICE').map((item) => item.name);
  if (services.length) return services.join(', ');
  const products = lineItems.filter((item) => item.type === 'PRODUCT').map((item) => item.name);
  if (products.length) return products.join(', ');
  return fallback;
}

export function computeAmountDue(lineItems: NormalizedLineItem[]) {
  return lineItems.reduce((sum, item) => sum + item.subtotal, 0);
}

function productQuantityMap(items: NormalizedLineItem[]) {
  const map = new Map<string, number>();
  for (const item of items) {
    if (item.type !== 'PRODUCT' || !item.refId) continue;
    map.set(item.refId, (map.get(item.refId) || 0) + item.quantity);
  }
  return map;
}

export async function applyProductLineItems(
  appointmentId: string,
  nextItems: NormalizedLineItem[],
  previousItems: NormalizedLineItem[] = [],
  performedBy: string | null = null
) {
  const prevMap = productQuantityMap(previousItems);
  const nextMap = productQuantityMap(nextItems);
  const productIds = new Set([...Array.from(prevMap.keys()), ...Array.from(nextMap.keys())]);

  for (const productId of Array.from(productIds)) {
    const prevQty = prevMap.get(productId) || 0;
    const nextQty = nextMap.get(productId) || 0;
    const delta = nextQty - prevQty;
    if (!delta) continue;

    const product = await Product.findById(productId);
    if (!product) {
      throw new Error('Product not found');
    }

    if (delta > 0) {
      if (product.quantity < delta) {
        throw new Error(`Insufficient stock for ${product.name}`);
      }
      product.quantity -= delta;
      await product.save();
      await StockMovement.create({
        productId,
        type: 'OUT',
        quantity: delta,
        reason: 'Appointment sale',
        appointmentId,
        performedBy,
      });
      continue;
    }

    const restoreQty = Math.abs(delta);
    product.quantity += restoreQty;
    await product.save();
    await StockMovement.create({
      productId,
      type: 'IN',
      quantity: restoreQty,
      reason: 'Appointment line item adjusted',
      appointmentId,
      performedBy,
    });
  }
}
