import prisma from "../config/prisma.js";
import { Prisma } from "../generated/prisma/client.js";

const ITEMS_INCLUDE = {
  items: {
    include: {
      vegetable: { select: { id: true, name: true } },
    },
    orderBy: { id: "asc" as const },
  },
  customer: { select: { id: true, name: true } },
};

export class QuotationRepository {
  // ── Create ──────────────────────────────────────────────────────────────────
  async create(data: {
    quotationNo: string;
    customerId?: bigint | null;
    customerName: string;
    quotationDate: Date;
    amount: Prisma.Decimal;
    extraCharge: Prisma.Decimal;
    discount: Prisma.Decimal;
    totalAmount: Prisma.Decimal;
    createdBy?: bigint | null;
    items: {
      vegetableId?: bigint | null;
      vegName: string;
      hsnCode?: string;
      quantity: Prisma.Decimal;
      unit: string;
      price: Prisma.Decimal;
      amount: Prisma.Decimal;
      createdBy?: bigint | null;
    }[];
  }) {
    const { items, ...quotationFields } = data;
    return prisma.quotation.create({
      data: {
        ...quotationFields,
        items: {
          create: items.map((item) => ({
            ...item,
            createdBy: item.createdBy ?? quotationFields.createdBy ?? null,
          })),
        },
      },
      include: ITEMS_INCLUDE,
    });
  }

  // ── Update ──────────────────────────────────────────────────────────────────
  async update(
    id: bigint,
    data: {
      customerId?: bigint | null;
      customerName: string;
      quotationDate: Date;
      amount: Prisma.Decimal;
      extraCharge: Prisma.Decimal;
      discount: Prisma.Decimal;
      totalAmount: Prisma.Decimal;
      items: {
        vegetableId?: bigint | null;
        vegName: string;
        hsnCode?: string;
        quantity: Prisma.Decimal;
        unit: string;
        price: Prisma.Decimal;
        amount: Prisma.Decimal;
      }[];
    }
  ) {
    const { items, ...quotationFields } = data;

    return prisma.$transaction(async (tx) => {
      // Delete old items and replace with new ones
      await tx.quotationItem.deleteMany({ where: { quotationId: id } });

      return tx.quotation.update({
        where: { id },
        data: {
          ...quotationFields,
          items: { create: items },
        },
        include: ITEMS_INCLUDE,
      });
    });
  }

  // ── Find all (paginated + search) ───────────────────────────────────────────
  async findAll(
    skip: number,
    take: number,
    search?: string,
    dateFrom?: Date,
    dateTo?: Date
  ) {
    const where: Prisma.QuotationWhereInput = {};

    if (search) {
      where.OR = [
        { quotationNo: { contains: search } },
        { customerName: { contains: search } },
      ];
    }

    if (dateFrom || dateTo) {
      where.quotationDate = {};
      if (dateFrom) where.quotationDate.gte = dateFrom;
      if (dateTo) where.quotationDate.lte = dateTo;
    }

    const [items, total] = await Promise.all([
      prisma.quotation.findMany({
        where,
        include: ITEMS_INCLUDE,
        orderBy: { id: 'desc' },
        skip,
        take,
      }),
      prisma.quotation.count({ where }),
    ]);

    return { items, total };
  }

  // ── Find by id ──────────────────────────────────────────────────────────────
  async findById(id: bigint) {
    return prisma.quotation.findUnique({
      where: { id },
      include: ITEMS_INCLUDE,
    });
  }

  // ── Delete ──────────────────────────────────────────────────────────────────
  async delete(id: bigint) {
    return prisma.quotation.delete({ where: { id } });
  }

  // ── Max ID for safe sequential number generation ─────────────────────────
  // count() breaks after deletions; max(id) is always monotonically increasing.
  async findMaxId(): Promise<number> {
    const result = await prisma.quotation.aggregate({ _max: { id: true } });
    return Number(result._max.id ?? 0);
  }

  // ── Uniqueness check for quotation number ────────────────────────────────
  async findByQuotationNo(quotationNo: string) {
    return prisma.quotation.findFirst({ where: { quotationNo } });
  }
}
