import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { BoxCashDocument } from '@schemas/box-cash.schema';
import { CashCountDocument } from '@schemas/cash-count.schema';
import { SaleDocument } from '@schemas/sale.schema';
import { UserDocument } from '@schemas/user.schema';
import { Model } from 'mongoose';

@Injectable()
export class MetricsService {
  constructor(
    @InjectModel('users') private userModel: Model<UserDocument>,
    @InjectModel('sales') private saleModel: Model<SaleDocument>,
    @InjectModel('boxcash') private boxModel: Model<BoxCashDocument>,
    @InjectModel('cashcount')
    private readonly corteCajaModel: Model<CashCountDocument>,
  ) {}

  async setSmallBox(dto: { caja_chica: number }, userId: string): Promise<any> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const box = await this.boxModel
      .findOne({ businessId: user.businessId })
      .exec();

    if (box && box._id) {
      const doc = await this.boxModel.findByIdAndUpdate(
        box._id,
        {
          ...dto,
          userId: userId,
        },
        {
          new: true,
        },
      );

      if (!doc)
        throw new HttpException('Item no encontrado', HttpStatus.NOT_FOUND);
      return doc;
    } else {
      return this.boxModel.create({
        businessId: user.businessId,
        userId: userId,
        ...dto,
      });
    }
  }

  async getSmallBox(userId: string): Promise<any> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const doc = await this.boxModel
      .findOne({ businessId: user.businessId })
      .populate('userId')
      .exec();

    if (!doc) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    return doc;
  }

  async findDailySales(
    userId: string,
    startDate: string | null,
    endDate: string | null,
  ): Promise<any> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const today = new Date();
    const start = startDate
      ? new Date(startDate)
      : new Date(today.setHours(0, 0, 0, 0));

    const end = endDate
      ? new Date(endDate)
      : new Date(today.setHours(23, 59, 59, 999));

    const result = await this.saleModel.aggregate([
      {
        $match: {
          businessId: user.businessId,
          createdAt: {
            $gte: start,
            $lte: end,
          },
        },
      },
      {
        $group: {
          _id: '$payment_type',
          count: { $sum: 1 },
          total_sub_total: { $sum: '$sub_total' },
          total_total: { $sum: '$total' },
          total_commission: { $sum: '$commission' },
          total_payment: { $sum: '$payment' },
          total_cancel: { $sum: '$cancel_amount' },
        },
      },
      {
        $project: {
          payment_type: '$_id',
          count: 1,
          total_sub_total: 1,
          total_total: 1,
          total_commission: 1,
          total_payment: 1,
          total_cancel: 1,
          _id: 0,
        },
      },
      {
        $sort: { payment_type: 1 },
      },
    ]);

    return result;
  }

  async findDailyProductsSales(
    userId: string,
    startDate: string | null,
    endDate: string | null,
  ): Promise<any> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const today = new Date();
    const start = startDate
      ? new Date(startDate)
      : new Date(today.setHours(0, 0, 0, 0));

    const end = endDate
      ? new Date(endDate)
      : new Date(today.setHours(23, 59, 59, 999));

    const result = await this.saleModel.aggregate([
      {
        $match: {
          businessId: user.businessId,
          createdAt: {
            $gte: start,
            $lte: end,
          },
        },
      },
      {
        // Descomponemos el array de productos
        $unwind: '$products',
      },
      {
        // Agrupamos por categoria de producto
        $group: {
          _id: '$products.categoria',
          total_items: { $sum: 1 }, // número de veces que aparece la categoría
          total_cantidad: { $sum: '$products.cantidad' }, // suma de unidades vendidas
          total_costo_venta: { $sum: '$products.costo_venta' }, // suma del costo
        },
      },
      {
        $project: {
          categoria: '$_id',
          total_items: 1,
          total_cantidad: 1,
          total_costo_venta: 1,
          _id: 0,
        },
      },
      {
        $sort: { categoria: 1 },
      },
    ]);

    return result;
  }

  async findWeeklySales(
    userId: string,
    startDate: string | null,
  ): Promise<any> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const inputDate = startDate ? new Date(startDate) : new Date();

    // día de la semana en formato JS: 0 = domingo, 1 = lunes, ...
    let day = inputDate.getDay();
    if (day === 0) day = 7; // domingo -> 7

    // lunes de la semana actual (hora local)
    const monday = new Date(inputDate);
    monday.setDate(inputDate.getDate() - (day - 1));
    monday.setHours(0, 0, 0, 0);

    // domingo de la misma semana (hora local)
    const sunday = new Date(monday);
    sunday.setDate(monday.getDate() + 6);
    sunday.setHours(23, 59, 59, 999);

    // Pipeline simplificado que devuelve solo los días con ventas
    const result = await this.saleModel.aggregate([
      {
        $addFields: {
          localCreatedAt: {
            $dateAdd: { startDate: '$createdAt', unit: 'hour', amount: -6 },
          },
        },
      },
      {
        $match: {
          businessId: user.businessId,
          localCreatedAt: { $gte: monday, $lte: sunday },
          cancel: { $ne: true },
        },
      },
      {
        $addFields: {
          dayOfWeek: { $dayOfWeek: '$localCreatedAt' },
        },
      },
      {
        $facet: {
          pagos: [
            {
              $match: { payment_type: { $in: ['pago', 'pago-a', 'pago-s'] } },
            },
            {
              $group: {
                _id: {
                  dayOfWeek: '$dayOfWeek',
                  metodo: '$remaining_pay', // cash o card
                },
                totalRemaining: { $sum: '$remaining' },
                count: { $sum: 1 },
              },
            },
            {
              $group: {
                _id: '$_id.dayOfWeek',
                methods: {
                  $push: {
                    metodo: '$_id.metodo',
                    totalRemaining: '$totalRemaining',
                    count: '$count',
                  },
                },
              },
            },
            {
              $project: {
                _id: 0,
                dayOfWeek: '$_id',
                methods: 1,
              },
            },
          ],
          otros: [
            // Etapa 1: Marcar ventas con productos
            {
              $addFields: {
                tieneProductos: {
                  $cond: [{ $gt: [{ $size: '$products' }, 0] }, true, false],
                },
                tienePremios: {
                  $cond: [
                    {
                      $and: [
                        { $eq: [{ $size: '$products' }, 0] },
                        { $gt: [{ $size: '$products_with_prizes' }, 0] },
                      ],
                    },
                    true,
                    false,
                  ],
                },
              },
            },
            // Etapa 2: Filtrar solo los que son productos o premios
            {
              $match: {
                $or: [{ tieneProductos: true }, { tienePremios: true }],
              },
            },
            // Etapa 3: Un solo agrupado para ambos
            {
              $group: {
                _id: {
                  dayOfWeek: '$dayOfWeek',
                  payment_type: '$payment_type',
                  tipo: {
                    $cond: [
                      { $eq: ['$tieneProductos', true] },
                      'ventasConProductos',
                      'premiosSinProductos',
                    ],
                  },
                },
                count: { $sum: 1 },
                total: { $sum: '$total' },
                sub_total: { $sum: '$sub_total' },
                prize: { $sum: '$prize' },
                remaining: { $sum: '$remaining' },
                commission: { $sum: '$commission' },
                payment: { $sum: '$payment' },
                partial_cash: { $sum: '$partial_cash' },
                partial_card: { $sum: '$partial_card' },
              },
            },
            // Etapa 4: Agrupar por día de la semana
            {
              $group: {
                _id: '$_id.dayOfWeek',
                paymentTypes: {
                  $push: {
                    payment_type: '$_id.payment_type',
                    tipo: '$_id.tipo',
                    count: '$count',
                    total: '$total',
                    sub_total: '$sub_total',
                    prize: '$prize',
                    remaining: '$remaining',
                    commission: '$commission',
                    payment: '$payment',
                    partial_cash: '$partial_cash',
                    partial_card: '$partial_card',
                  },
                },
              },
            },
            {
              $project: {
                _id: 0,
                dayOfWeek: '$_id',
                paymentTypes: 1,
              },
            },
            { $sort: { dayOfWeek: 1 } },
          ],
        },
      },
    ]);

    return result;
  }

  async findDailySalesTest(
    userId: string,
    startDate: string | null,
    endDate: string | null,
  ): Promise<any> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const today = new Date();
    const start = startDate
      ? new Date(startDate)
      : new Date(today.setHours(0, 0, 0, 0));

    const end = endDate ? new Date(endDate) : new Date();
    end.setHours(23, 59, 59, 999);

    const result = await this.saleModel.aggregate([
      {
        $addFields: {
          localCreatedAt: {
            $dateAdd: { startDate: '$createdAt', unit: 'hour', amount: -6 },
          },
        },
      },
      {
        $match: {
          businessId: user.businessId,
          turno_terminado: '',
          cancel: false,
          localCreatedAt: {
            $gte: start,
            $lte: end,
          },
        },
      },
      {
        $facet: {
          pagos: [
            { $match: { payment_type: { $in: ['pago', 'pago-a', 'pago-s'] } } },
            {
              $group: {
                _id: '$remaining_pay', // cash o card
                totalRemaining: { $sum: '$remaining' },
                totalCommission: { $sum: '$commission' },
              },
            },
          ],

          ventasConProductos: [
            { $match: { 'products.0': { $exists: true } } },
            {
              $group: {
                _id: '$payment_type',
                subtotalVentas: { $sum: '$sub_total' },
                totalVentas: { $sum: '$total' },
                totalRemaining: { $sum: '$remaining' },
                totalPayment: { $sum: '$payment' },
                totalPrize: { $sum: '$prize' },
                totalCommission: { $sum: '$commission' },
                totalPartialCash: { $sum: '$partial_cash' },
                totalPartialCard: { $sum: '$partial_card' },
                ventas: { $push: '$$ROOT' },
              },
            },
            { $unwind: '$ventas' },
            { $unwind: '$ventas.products' },
            {
              $group: {
                _id: {
                  payment_type: '$_id',
                  categoria: '$ventas.products.categoria',
                  clave: '$ventas.products.clave',
                  exists: '$ventas.products.exists',
                  bet: '$ventas.products.bet',
                },
                cantidadTotal: { $sum: '$ventas.products.cantidad' },
                costoTotal: {
                  $sum: {
                    $multiply: [
                      '$ventas.products.costo_venta',
                      '$ventas.products.cantidad',
                    ],
                  },
                },
                subtotalVentas: { $first: '$subtotalVentas' },
                totalRemaining: { $first: '$totalRemaining' },
                totalPayment: { $first: '$totalPayment' },
                totalPrize: { $first: '$totalPrize' },
                totalVentas: { $first: '$totalVentas' },
                totalCommission: { $first: '$totalCommission' },
                totalPartialCash: { $first: '$totalPartialCash' },
                totalPartialCard: { $first: '$totalPartialCard' },
              },
            },
            {
              $group: {
                _id: '$_id.payment_type',
                subtotalVentas: { $first: '$subtotalVentas' },
                totalRemaining: { $first: '$totalRemaining' },
                totalPayment: { $first: '$totalPayment' },
                totalPrize: { $first: '$totalPrize' },
                totalVentas: { $first: '$totalVentas' },
                totalCommission: { $first: '$totalCommission' },
                totalPartialCash: { $first: '$totalPartialCash' },
                totalPartialCard: { $first: '$totalPartialCard' },
                productos: {
                  $push: {
                    categoria: '$_id.categoria',
                    clave: '$_id.clave',
                    cantidad: '$cantidadTotal',
                    costo_total: '$costoTotal',
                    exists: '$_id.exists',
                    bet: '$_id.bet',
                  },
                },
              },
            },
          ],

          premiosSinProductos: [
            {
              $match: {
                products: { $size: 0 },
                'products_with_prizes.0': { $exists: true },
              },
            },
            {
              $group: {
                _id: '$payment_type',
                subtotalVentas: { $sum: '$sub_total' },
                totalVentas: { $sum: '$total' },
                totalRemaining: { $sum: '$remaining' },
                totalPayment: { $sum: '$payment' },
                totalPrize: { $sum: '$prize' },
                totalCommission: { $sum: '$commission' },
                totalPartialCash: { $sum: '$partial_cash' },
                totalPartialCard: { $sum: '$partial_card' },
                spventas: { $push: '$$ROOT' },
              },
            },
            { $unwind: '$spventas' },
            { $unwind: '$spventas.products_with_prizes' },
            {
              $group: {
                _id: {
                  payment_type: '$_id',
                  categoria: '$spventas.products_with_prizes.categoria',
                  clave: '$spventas.products_with_prizes.clave',
                  exists: '$spventas.products_with_prizes.exists',
                  bet: '$spventas.products_with_prizes.bet',
                },
                cantidadTotal: {
                  $sum: '$spventas.products_with_prizes.cantidad',
                },
                costoTotal: {
                  $sum: {
                    $multiply: [
                      '$spventas.products_with_prizes.costo_venta',
                      '$spventas.products_with_prizes.cantidad',
                    ],
                  },
                },
                subtotalVentas: { $first: '$subtotalVentas' },
                totalRemaining: { $first: '$totalRemaining' },
                totalPayment: { $first: '$totalPayment' },
                totalPrize: { $first: '$totalPrize' },
                totalVentas: { $first: '$totalVentas' },
                totalCommission: { $first: '$totalCommission' },
                totalPartialCash: { $first: '$totalPartialCash' },
                totalPartialCard: { $first: '$totalPartialCard' },
              },
            },
            {
              $group: {
                _id: '$_id.payment_type',
                subtotalVentas: { $first: '$subtotalVentas' },
                totalRemaining: { $first: '$totalRemaining' },
                totalPayment: { $first: '$totalPayment' },
                totalPrize: { $first: '$totalPrize' },
                totalVentas: { $first: '$totalVentas' },
                totalCommission: { $first: '$totalCommission' },
                totalPartialCash: { $first: '$totalPartialCash' },
                totalPartialCard: { $first: '$totalPartialCard' },
                productos: {
                  $push: {
                    categoria: '$_id.categoria',
                    clave: '$_id.clave',
                    cantidad: '$cantidadTotal',
                    costo_total: '$costoTotal',
                    exists: '$_id.exists',
                    bet: '$_id.bet',
                  },
                },
              },
            },
          ],
        },
      },

      // Reorganizar el resultado como { pagos, otros: { ventasConProductos, premiosSinProductos } }
      {
        $project: {
          pagos: 1,
          otros: {
            ventasConProductos: '$ventasConProductos',
            premiosSinProductos: '$premiosSinProductos',
          },
        },
      },
    ]);

    return result;
  }

  async findDailyCorteCaja(userId: string, startDate: string, endDate: string) {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const selectedDate = new Date(startDate + 'T00:00:00-06:00'); // Inicio del día en hora de México
    const nextDate = new Date(endDate + 'T23:59:59.999-06:00');

    return this.corteCajaModel
      .find({
        businessId: user.businessId,
        corte_terminado: { $ne: '' },
        createdAt: {
          $gte: selectedDate,
          $lte: nextDate,
        },
      })
      .exec();
  }

  async findDailyComision(
    userId: string,
    startDate: string,
    endDate: string,
  ): Promise<any[]> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const selectedDate = new Date(startDate + 'T00:00:00-06:00'); // Inicio del día en hora de México
    const nextDate = new Date(endDate + 'T23:59:59.999-06:00');

    const comision = await this.saleModel.aggregate([
      {
        $match: {
          businessId: user.businessId,
          createdAt: { $gte: selectedDate, $lte: nextDate },
          turno_terminado: { $ne: '' },
          cancel: { $ne: true },
        },
      },
      { $unwind: '$products' },
      {
        $lookup: {
          from: 'products',
          localField: 'products.productId',
          foreignField: '_id',
          as: 'productInfo',
        },
      },
      { $unwind: '$productInfo' },
      {
        $addFields: {
          productCommission: {
            $multiply: [
              { $multiply: ['$products.costo_venta', '$products.cantidad'] },
              { $divide: ['$productInfo.comision', 100] },
            ],
          },
        },
      },
      {
        $group: {
          _id: { venta: '$_id', turno: '$turno_terminado' }, // 👈 agrupamos venta dentro del turno
          totalSale: { $first: '$total' },
          createdAt: { $first: '$createdAt' }, // 👈 lo guardamos para poder ordenar
          payment_type: { $first: '$payment_type' },
          commissionTotal: { $sum: '$productCommission' },
          products: {
            $push: {
              productId: '$products.productId',
              identificador: '$productInfo.identificador',
              categoria: '$products.categoria',
              clave: '$products.clave',
              sorteo: '$products.sorteo',
              fecha: '$products.fecha',
              cantidad: '$products.cantidad',
              costo_venta: '$products.costo_venta',
              comision: '$productInfo.comision',
              commission: '$productCommission',
            },
          },
        },
      },
      // 👇 sort por fecha de venta (más reciente primero)
      { $sort: { createdAt: -1 } },
      {
        $group: {
          _id: '$_id.turno', // 👈 ahora agrupamos por turno
          ventas: {
            $push: {
              ventaId: '$_id.venta',
              totalSale: '$totalSale',
              createdAt: '$createdAt', // 👈 lo guardamos para poder ordenar
              payment_type: '$payment_type',
              commissionTotal: '$commissionTotal',
              products: '$products',
            },
          },
          commissionTotalTurno: { $sum: '$commissionTotal' },
        },
      },
      { $sort: { _id: 1 } },
    ]);

    return comision;
  }

  async findMonthlyComision(
    userId: string,
    startDate: string,
    endDate: string,
  ): Promise<any[]> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const today = new Date();
    const start = startDate
      ? new Date(startDate)
      : new Date(today.setHours(0, 0, 0, 0));

    const end = endDate
      ? new Date(endDate)
      : new Date(today.setHours(23, 59, 59, 999));

    const resumenMensual = await this.corteCajaModel.aggregate([
      // Ajuste de zona horaria
      {
        $addFields: {
          localCreatedAt: {
            $dateAdd: { startDate: '$createdAt', unit: 'hour', amount: -6 },
          },
        },
      },
      // Filtro por rango
      {
        $match: {
          businessId: user.businessId,
          localCreatedAt: { $gte: start, $lte: end },
        },
      },
      {
        $lookup: {
          from: 'comisions',
          localField: '_id',
          foreignField: 'cashcountId',
          as: 'comision',
        },
      },
      { $unwind: { path: '$comision', preserveNullAndEmptyArrays: true } },
      // Formato de fecha YYYY-MM-DD
      {
        $addFields: {
          saleDay: {
            $dateToString: { format: '%Y-%m-%d', date: '$localCreatedAt' },
          },
        },
      },

      // 1er agrupado: día + turno
      {
        $group: {
          _id: {
            day: '$saleDay',
            turno: '$turno',
          },
          turno: { $first: '$turno' },
          createdAt: { $first: '$createdAt' },
          corte_caja: { $first: '$$ROOT' },
          corteId: { $first: '$_id' },
        },
      },

      // Lookup de ventas completas (NO unwind todavía)
      {
        $lookup: {
          from: 'sales',
          localField: 'corteId',
          foreignField: 'cashcountId',
          as: 'ventas',
        },
      },

      // 3. Calcular totales de vales
      {
        $addFields: {
          total_vales: { $sum: '$corte_caja.vales_items.monto' },
        },
      },

      // ---- 🔹 generar resumen de productos ----
      {
        $lookup: {
          from: 'sales',
          let: { corteId: '$corteId' },
          pipeline: [
            { $match: { $expr: { $eq: ['$cashcountId', '$$corteId'] } } },
            { $unwind: '$products' },
            // Lookup de ventas completas (NO unwind todavía)
            {
              $lookup: {
                from: 'products',
                localField: 'products.productId',
                foreignField: '_id',
                as: 'productInfo',
              },
            },
            {
              $unwind: {
                path: '$productInfo',
                preserveNullAndEmptyArrays: true,
              },
            },
            {
              $group: {
                //_id: '$products.productId',
                _id: {
                  productId: '$products.productId',
                  sorteo: '$products.sorteo',
                },
                categoria: { $first: '$products.categoria' },
                clave: { $first: '$products.clave' },
                fecha: { $first: '$products.fecha' },
                sorteo: { $first: '$products.sorteo' },
                costo_venta: { $first: '$products.costo_venta' },
                totalCantidad: { $sum: '$products.cantidad' },
                comision: { $first: '$productInfo.comision' },
                productComision: {
                  $sum: {
                    $multiply: [
                      {
                        $multiply: [
                          '$products.costo_venta',
                          '$products.cantidad',
                        ],
                      },
                      { $divide: ['$productInfo.comision', 100] },
                    ],
                  },
                },
                cost_venta: { $first: '$products.costo_venta' },
                total_venta: {
                  $sum: {
                    $multiply: ['$products.cantidad', '$products.costo_venta'],
                  },
                },
              },
            },
          ],
          as: 'productos',
        },
      },

      // Agrupado final solo por día
      {
        $group: {
          _id: '$_id.day',
          turnos: {
            $push: {
              turno: '$turno',
              ventas: '$ventas',
              corte_caja: '$corte_caja',
              productos: '$productos',
              total_vales: '$total_vales',
            },
          },
        },
      },

      { $sort: { _id: 1 } },
    ]);
    return resumenMensual;
  }

  async findMonthlyBalance(
    userId: string,
    startDate: string,
    endDate: string,
  ): Promise<any[]> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const today = new Date();
    const start = startDate
      ? new Date(startDate)
      : new Date(today.setHours(0, 0, 0, 0));

    const end = endDate
      ? new Date(endDate)
      : new Date(today.setHours(23, 59, 59, 999));

    const balance = await this.corteCajaModel.aggregate([
      // Ajuste de zona horaria
      {
        $addFields: {
          dia: {
            $dateAdd: { startDate: '$createdAt', unit: 'hour', amount: -6 },
          },
        },
      },
      // 1. Filtro por rango
      {
        $match: {
          businessId: user.businessId,
          dia: { $gte: start, $lte: end },
        },
      },
      // 2. Traer las ventas relacionadas por cashcountId
      {
        $lookup: {
          from: 'sales',
          localField: '_id',
          foreignField: 'cashcountId',
          as: 'ventas_turno',
        },
      },

      // 3. Calcular totales de vales
      {
        $addFields: {
          total_vales: { $sum: '$vales_items.monto' },
        },
      },

      // Formato de fecha YYYY-MM-DD
      {
        $addFields: {
          saleDay: {
            $dateToString: { format: '%Y-%m-%d', date: '$dia' },
          },
        },
      },

      // 4. Agrupar por día + turno
      {
        $group: {
          _id: {
            dia: '$saleDay',
          },
          cortes: { $push: '$$ROOT' },
          // ejemplo: sumar ventas de todos los sales del turno
          totalVentasTurno: { $sum: { $size: '$ventas_turno' } },
          totalValesTurno: { $sum: '$total_vales' },
        },
      },

      // 5. Ordenar por fecha y turno
      {
        $sort: {
          '_id.dia': 1,
          '_id.turno': 1,
        },
      },
    ]);

    return balance;
  }

  async findDailyFull(
    userId: string,
    startDate: string,
    endDate: string,
    turno: string = '',
  ): Promise<any[]> {
    const user = await this.userModel.findById(userId).exec();
    if (!user) {
      throw new HttpException('Datos incorrectos', HttpStatus.NOT_FOUND);
    }

    const selectedDate = new Date(startDate + 'T00:00:00-06:00'); // Inicio del día en hora de México
    const nextDate = new Date(endDate + 'T23:59:59.999-06:00');

    const ventas = await this.saleModel.aggregate([
      {
        $match: {
          createdAt: { $gte: selectedDate, $lte: nextDate },
          turno_terminado: { $eq: turno },
        },
      },
      // Populate de products.productId
      {
        $lookup: {
          from: 'products',
          localField: 'products.productId',
          foreignField: '_id',
          as: 'products_populated',
        },
      },
      {
        $addFields: {
          products: {
            $map: {
              input: '$products',
              as: 'item',
              in: {
                $let: {
                  vars: {
                    productObj: {
                      $arrayElemAt: [
                        {
                          $filter: {
                            input: '$products_populated',
                            as: 'pop',
                            cond: { $eq: ['$$pop._id', '$$item.productId'] },
                          },
                        },
                        0,
                      ],
                    },
                    totalItem: {
                      $multiply: ['$$item.cantidad', '$$item.costo_venta'],
                    },
                  },
                  in: {
                    $mergeObjects: [
                      '$$item',
                      {
                        product: '$$productObj',
                        total_item: '$$totalItem',
                        commission_total: {
                          $cond: [
                            { $ifNull: ['$$productObj.comision', false] },
                            {
                              $divide: [
                                {
                                  $multiply: [
                                    '$$totalItem',
                                    '$$productObj.comision',
                                  ],
                                },
                                100,
                              ],
                            },
                            0,
                          ],
                        },
                      },
                    ],
                  },
                },
              },
            },
          },
        },
      },
      // Populate de products_with_prizes.productId
      {
        $lookup: {
          from: 'products',
          localField: 'products_with_prizes.productId',
          foreignField: '_id',
          as: 'products_with_prizes_populated',
        },
      },
      {
        $addFields: {
          products_with_prizes: {
            $map: {
              input: '$products_with_prizes',
              as: 'item',
              in: {
                $let: {
                  vars: {
                    productObj: {
                      $arrayElemAt: [
                        {
                          $filter: {
                            input: '$products_with_prizes_populated',
                            as: 'pop',
                            cond: { $eq: ['$$pop._id', '$$item.productId'] },
                          },
                        },
                        0,
                      ],
                    },
                    totalItem: {
                      $multiply: ['$$item.cantidad', '$$item.costo_venta'],
                    },
                  },
                  in: {
                    $mergeObjects: [
                      '$$item',
                      {
                        product: '$$productObj',
                        total_item: '$$totalItem',
                        commission_total: {
                          $cond: [
                            { $ifNull: ['$$productObj.comision', false] },
                            {
                              $divide: [
                                {
                                  $multiply: [
                                    '$$totalItem',
                                    '$$productObj.comision',
                                  ],
                                },
                                100,
                              ],
                            },
                            0,
                          ],
                        },
                      },
                    ],
                  },
                },
              },
            },
          },
        },
      },
      // Limpiamos campos temporales
      {
        $project: {
          products_populated: 0,
          products_with_prizes_populated: 0,
        },
      },
      // Orden descendente por fecha
      {
        $sort: { createdAt: -1 },
      },
    ]);

    return ventas;
  }
}
