import Sale from '../models/Sale.js';
import * as returnRepo from './saleReturnRepository.js';

export const findAll = async ({ search, startDate, endDate, page = 1, limit = 20, cashierId }) => {
  const query = {};
  if (search) {
    query.$or = [
      { billNumber: { $regex: search, $options: 'i' } },
      { customerName: { $regex: search, $options: 'i' } },
      { customerPhone: { $regex: search, $options: 'i' } },
    ];
  }
  if (cashierId) query['cashier.id'] = cashierId;
  if (startDate || endDate) {
    query.createdAt = {};
    if (startDate) query.createdAt.$gte = new Date(startDate);
    if (endDate) query.createdAt.$lte = new Date(endDate);
  }

  const skip = (Number(page) - 1) * Number(limit);
  const [sales, total] = await Promise.all([
    Sale.find(query).sort('-createdAt').skip(skip).limit(Number(limit)),
    Sale.countDocuments(query),
  ]);

  return { sales, total, page: Number(page), pages: Math.ceil(total / Number(limit)) };
};

export const findById = async (id) => Sale.findById(id).populate('items.product', 'name category sellingPrice image trackingType unit');

export const findLatest = async () => Sale.findOne().sort('-createdAt');

export const create = async (data, session) => {
  const sale = new Sale(data);
  await sale.save({ session });
  return sale;
};

export const aggregateSales = async (startDate, endDate) => {
  const [salesResult, refunds] = await Promise.all([
    Sale.aggregate([
      { $match: { createdAt: { $gte: startDate, $lte: endDate } } },
      { $group: { _id: null, totalSales: { $sum: '$grandTotal' }, count: { $sum: 1 }, totalDiscount: { $sum: '$discount' } } },
    ]),
    returnRepo.sumRefundsBetween(startDate, endDate),
  ]);
  const base = salesResult[0] || { totalSales: 0, count: 0, totalDiscount: 0 };
  return [
    {
      ...base,
      totalRefunds: refunds.total,
      totalSales: Math.round((base.totalSales - refunds.total) * 100) / 100,
    },
  ];
};

export const aggregateDailySales = async (startDate, endDate) => {
  const [salesDaily, refundDaily] = await Promise.all([
    Sale.aggregate([
      { $match: { createdAt: { $gte: startDate, $lte: endDate } } },
      { $group: { _id: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } }, totalSales: { $sum: '$grandTotal' }, count: { $sum: 1 } } },
      { $sort: { _id: 1 } },
    ]),
    returnRepo.aggregateDailyRefunds(startDate, endDate),
  ]);
  const refundMap = new Map(refundDaily.map((r) => [r._id, r.total]));
  return salesDaily.map((d) => ({
    ...d,
    totalRefunds: refundMap.get(d._id) || 0,
    totalSales: Math.round((d.totalSales - (refundMap.get(d._id) || 0)) * 100) / 100,
  }));
};

export const bestSelling = async (limit = 10) => {
  const sold = await Sale.aggregate([
    { $unwind: '$items' },
    { $group: { _id: '$items.product', name: { $first: '$items.productName' }, quantity: { $sum: '$items.quantity' }, totalRevenue: { $sum: '$items.total' } } },
  ]);
  const returned = await returnRepo.aggregateReturnedQuantities(new Date(0), new Date());
  const returnedMap = new Map(returned.map((r) => [String(r._id), r.quantity]));
  return sold
    .map((s) => ({
      ...s,
      quantity: s.quantity - (returnedMap.get(String(s._id)) || 0),
    }))
    .sort((a, b) => b.quantity - a.quantity)
    .slice(0, Number(limit));
};

export const getTodaySales = async () => {
  const start = new Date();
  start.setHours(0, 0, 0, 0);
  const end = new Date();
  end.setHours(23, 59, 59, 999);
  const [result, refunds] = await Promise.all([
    Sale.aggregate([
      { $match: { createdAt: { $gte: start, $lte: end } } },
      { $group: { _id: null, totalSales: { $sum: '$grandTotal' }, count: { $sum: 1 } } },
    ]),
    returnRepo.sumRefundsBetween(start, end),
  ]);
  const base = result[0] || { totalSales: 0, count: 0 };
  return {
    ...base,
    totalRefunds: refunds.total,
    totalSales: Math.round((base.totalSales - refunds.total) * 100) / 100,
  };
};

export const getSalesChart = async (days = 7) => {
  const start = new Date();
  start.setDate(start.getDate() - days);
  start.setHours(0, 0, 0, 0);
  const end = new Date();
  end.setHours(23, 59, 59, 999);
  const [salesDaily, refundDaily] = await Promise.all([
    Sale.aggregate([
      { $match: { createdAt: { $gte: start } } },
      { $group: { _id: { $dateToString: { format: '%Y-%m-%d', date: '$createdAt' } }, totalSales: { $sum: '$grandTotal' }, count: { $sum: 1 } } },
      { $sort: { _id: 1 } },
    ]),
    returnRepo.aggregateDailyRefunds(start, end),
  ]);
  const refundMap = new Map(refundDaily.map((r) => [r._id, r.total]));
  return salesDaily.map((d) => ({
    ...d,
    totalRefunds: refundMap.get(d._id) || 0,
    totalSales: Math.round((d.totalSales - (refundMap.get(d._id) || 0)) * 100) / 100,
  }));
};

export const countDocuments = async () => Sale.countDocuments();
