/**
 * SalesOrderService - Servicio de órdenes de venta
 *
 * Gestión de órdenes de venta para unidades inmobiliarias
 * (departamentos, lotes, viviendas).
 * Soporta flujo Order-to-Cash completo.
 *
 * @module Sales (MAI-010)
 */

import { Repository, DataSource } from 'typeorm';
import { SalesOrder } from '../entities/sales-order.entity';
import { SalesOrderItem } from '../entities/sales-order-item.entity';
import { Quotation } from '../entities/quotation.entity';
import { QuotationItem } from '../entities/quotation-item.entity';

interface ServiceContext {
  tenantId: string;
  userId?: string;
  companyId?: string;
}

export interface CreateSalesOrderDto {
  quotationId?: string;
  partnerId: string;
  clientOrderRef?: string;
  orderDate?: Date;
  validityDate?: Date;
  commitmentDate?: Date;
  currencyId: string;
  pricelistId?: string;
  paymentTermId?: string;
  userId?: string;
  salesTeamId?: string;
  invoicePolicy?: 'order' | 'delivery';
  notes?: string;
  termsConditions?: string;
  items?: CreateSalesOrderItemDto[];
}

export interface UpdateSalesOrderDto {
  clientOrderRef?: string;
  validityDate?: Date;
  commitmentDate?: Date;
  pricelistId?: string;
  paymentTermId?: string;
  userId?: string;
  salesTeamId?: string;
  invoicePolicy?: 'order' | 'delivery';
  notes?: string;
  termsConditions?: string;
}

export interface CreateSalesOrderItemDto {
  productId?: string;
  productSku?: string;
  productName: string;
  description?: string;
  quantity: number;
  uom?: string;
  unitPrice: number;
  unitCost?: number;
  discountPercent?: number;
  taxRate?: number;
  lotNumber?: string;
  serialNumber?: string;
}

export interface UpdateSalesOrderItemDto {
  productName?: string;
  description?: string;
  quantity?: number;
  uom?: string;
  unitPrice?: number;
  unitCost?: number;
  discountPercent?: number;
  taxRate?: number;
  lotNumber?: string;
  serialNumber?: string;
}

export interface SalesOrderFilters {
  partnerId?: string;
  userId?: string;
  salesTeamId?: string;
  status?: string;
  invoiceStatus?: string;
  deliveryStatus?: string;
  dateFrom?: Date;
  dateTo?: Date;
  minTotal?: number;
  maxTotal?: number;
  search?: string;
  page?: number;
  limit?: number;
}

export class SalesOrderService {
  private readonly orderRepo: Repository<SalesOrder>;
  private readonly itemRepo: Repository<SalesOrderItem>;
  private readonly quotationRepo: Repository<Quotation>;
  private readonly quotationItemRepo: Repository<QuotationItem>;
  private readonly dataSource: DataSource;

  constructor(dataSource: DataSource) {
    this.dataSource = dataSource;
    this.orderRepo = dataSource.getRepository(SalesOrder);
    this.itemRepo = dataSource.getRepository(SalesOrderItem);
    this.quotationRepo = dataSource.getRepository(Quotation);
    this.quotationItemRepo = dataSource.getRepository(QuotationItem);
  }

  async findAll(
    ctx: ServiceContext,
    filters: SalesOrderFilters = {},
  ): Promise<{ data: SalesOrder[]; total: number; page: number; limit: number }> {
    const page = filters.page || 1;
    const limit = filters.limit || 50;
    const skip = (page - 1) * limit;

    const queryBuilder = this.orderRepo
      .createQueryBuilder('o')
      .where('o.tenant_id = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('o.deleted_at IS NULL');

    if (filters.partnerId) {
      queryBuilder.andWhere('o.partner_id = :partnerId', { partnerId: filters.partnerId });
    }

    if (filters.userId) {
      queryBuilder.andWhere('o.user_id = :userId', { userId: filters.userId });
    }

    if (filters.salesTeamId) {
      queryBuilder.andWhere('o.sales_team_id = :salesTeamId', { salesTeamId: filters.salesTeamId });
    }

    if (filters.status) {
      queryBuilder.andWhere('o.status = :status', { status: filters.status });
    }

    if (filters.invoiceStatus) {
      queryBuilder.andWhere('o.invoice_status = :invoiceStatus', { invoiceStatus: filters.invoiceStatus });
    }

    if (filters.deliveryStatus) {
      queryBuilder.andWhere('o.delivery_status = :deliveryStatus', { deliveryStatus: filters.deliveryStatus });
    }

    if (filters.dateFrom) {
      queryBuilder.andWhere('o.order_date >= :dateFrom', { dateFrom: filters.dateFrom });
    }

    if (filters.dateTo) {
      queryBuilder.andWhere('o.order_date <= :dateTo', { dateTo: filters.dateTo });
    }

    if (filters.minTotal !== undefined) {
      queryBuilder.andWhere('o.amount_total >= :minTotal', { minTotal: filters.minTotal });
    }

    if (filters.maxTotal !== undefined) {
      queryBuilder.andWhere('o.amount_total <= :maxTotal', { maxTotal: filters.maxTotal });
    }

    if (filters.search) {
      queryBuilder.andWhere(
        '(o.name ILIKE :search OR o.client_order_ref ILIKE :search)',
        { search: `%${filters.search}%` },
      );
    }

    const [data, total] = await queryBuilder
      .orderBy('o.created_at', 'DESC')
      .skip(skip)
      .take(limit)
      .getManyAndCount();

    return { data, total, page, limit };
  }

  async findById(ctx: ServiceContext, id: string): Promise<SalesOrder | null> {
    return this.orderRepo.findOne({
      where: {
        id,
        tenantId: ctx.tenantId,
      },
    });
  }

  async findByIdWithItems(ctx: ServiceContext, id: string): Promise<SalesOrder | null> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return null;
    }

    const items = await this.itemRepo.find({
      where: { orderId: id },
      order: { lineNumber: 'ASC' },
    });

    return { ...order, items } as SalesOrder & { items: SalesOrderItem[] };
  }

  async findByName(ctx: ServiceContext, name: string): Promise<SalesOrder | null> {
    return this.orderRepo.findOne({
      where: {
        name,
        tenantId: ctx.tenantId,
      },
    });
  }

  async findByPartner(ctx: ServiceContext, partnerId: string): Promise<SalesOrder[]> {
    return this.orderRepo
      .createQueryBuilder('o')
      .where('o.tenant_id = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('o.deleted_at IS NULL')
      .andWhere('o.partner_id = :partnerId', { partnerId })
      .orderBy('o.created_at', 'DESC')
      .getMany();
  }

  async findByQuotation(ctx: ServiceContext, quotationId: string): Promise<SalesOrder | null> {
    return this.orderRepo.findOne({
      where: {
        quotationId,
        tenantId: ctx.tenantId,
      },
    });
  }

  async findPendingDelivery(ctx: ServiceContext): Promise<SalesOrder[]> {
    return this.orderRepo
      .createQueryBuilder('o')
      .where('o.tenant_id = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('o.deleted_at IS NULL')
      .andWhere('o.status = :status', { status: 'sale' })
      .andWhere('o.delivery_status IN (:...statuses)', { statuses: ['pending', 'partial'] })
      .orderBy('o.commitment_date', 'ASC')
      .getMany();
  }

  async findPendingInvoice(ctx: ServiceContext): Promise<SalesOrder[]> {
    return this.orderRepo
      .createQueryBuilder('o')
      .where('o.tenant_id = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('o.deleted_at IS NULL')
      .andWhere('o.status = :status', { status: 'sale' })
      .andWhere('o.invoice_status IN (:...statuses)', { statuses: ['pending', 'partial'] })
      .orderBy('o.order_date', 'ASC')
      .getMany();
  }

  private async generateOrderName(ctx: ServiceContext): Promise<string> {
    const year = new Date().getFullYear();
    const prefix = `SO-${year}-`;

    const lastOrder = await this.orderRepo
      .createQueryBuilder('o')
      .where('o.tenant_id = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('o.name LIKE :prefix', { prefix: `${prefix}%` })
      .orderBy('o.name', 'DESC')
      .getOne();

    let sequence = 1;
    if (lastOrder) {
      const lastNumber = lastOrder.name.replace(prefix, '');
      sequence = parseInt(lastNumber, 10) + 1;
    }

    return `${prefix}${sequence.toString().padStart(5, '0')}`;
  }

  private calculateItemTotals(item: CreateSalesOrderItemDto): {
    discountAmount: number;
    taxAmount: number;
    subtotal: number;
    total: number;
  } {
    const quantity = Number(item.quantity) || 0;
    const unitPrice = Number(item.unitPrice) || 0;
    const discountPercent = Number(item.discountPercent) || 0;
    const taxRate = Number(item.taxRate) ?? 16;

    const grossAmount = quantity * unitPrice;
    const discountAmount = grossAmount * (discountPercent / 100);
    const subtotal = grossAmount - discountAmount;
    const taxAmount = subtotal * (taxRate / 100);
    const total = subtotal + taxAmount;

    return {
      discountAmount: Math.round(discountAmount * 100) / 100,
      taxAmount: Math.round(taxAmount * 100) / 100,
      subtotal: Math.round(subtotal * 100) / 100,
      total: Math.round(total * 100) / 100,
    };
  }

  private calculateOrderTotals(items: Array<{ subtotal: number; taxAmount: number }>): {
    amountUntaxed: number;
    amountTax: number;
    amountTotal: number;
  } {
    const amountUntaxed = items.reduce((sum, item) => sum + Number(item.subtotal), 0);
    const amountTax = items.reduce((sum, item) => sum + Number(item.taxAmount), 0);
    const amountTotal = amountUntaxed + amountTax;

    return {
      amountUntaxed: Math.round(amountUntaxed * 100) / 100,
      amountTax: Math.round(amountTax * 100) / 100,
      amountTotal: Math.round(amountTotal * 100) / 100,
    };
  }

  async create(ctx: ServiceContext, dto: CreateSalesOrderDto): Promise<SalesOrder> {
    const orderName = await this.generateOrderName(ctx);

    return this.dataSource.transaction(async (manager) => {
      const orderRepo = manager.getRepository(SalesOrder);
      const itemRepo = manager.getRepository(SalesOrderItem);

      const order = orderRepo.create({
        tenantId: ctx.tenantId,
        companyId: ctx.companyId || ctx.tenantId,
        createdBy: ctx.userId,
        name: orderName,
        quotationId: dto.quotationId,
        partnerId: dto.partnerId,
        clientOrderRef: dto.clientOrderRef,
        orderDate: dto.orderDate ?? new Date(),
        validityDate: dto.validityDate,
        commitmentDate: dto.commitmentDate,
        currencyId: dto.currencyId,
        pricelistId: dto.pricelistId,
        paymentTermId: dto.paymentTermId,
        userId: dto.userId ?? ctx.userId,
        salesTeamId: dto.salesTeamId,
        invoicePolicy: dto.invoicePolicy ?? 'order',
        notes: dto.notes,
        termsConditions: dto.termsConditions,
        status: 'draft',
        invoiceStatus: 'pending',
        deliveryStatus: 'pending',
        amountUntaxed: 0,
        amountTax: 0,
        amountTotal: 0,
      });

      const savedOrder = await orderRepo.save(order);

      if (dto.items && dto.items.length > 0) {
        const itemEntities: SalesOrderItem[] = [];

        for (let i = 0; i < dto.items.length; i++) {
          const itemDto = dto.items[i];
          const calculated = this.calculateItemTotals(itemDto);

          const item = itemRepo.create({
            orderId: savedOrder.id,
            lineNumber: i + 1,
            productId: itemDto.productId,
            productSku: itemDto.productSku,
            productName: itemDto.productName,
            description: itemDto.description,
            quantity: itemDto.quantity,
            quantityReserved: 0,
            quantityShipped: 0,
            quantityDelivered: 0,
            quantityReturned: 0,
            uom: itemDto.uom ?? 'PZA',
            unitPrice: itemDto.unitPrice,
            unitCost: itemDto.unitCost ?? 0,
            discountPercent: itemDto.discountPercent ?? 0,
            taxRate: itemDto.taxRate ?? 16,
            lotNumber: itemDto.lotNumber,
            serialNumber: itemDto.serialNumber,
            status: 'pending',
            ...calculated,
          });

          itemEntities.push(item);
        }

        await itemRepo.save(itemEntities);

        const totals = this.calculateOrderTotals(itemEntities);
        savedOrder.amountUntaxed = totals.amountUntaxed;
        savedOrder.amountTax = totals.amountTax;
        savedOrder.amountTotal = totals.amountTotal;

        await orderRepo.save(savedOrder);
      }

      return savedOrder;
    });
  }

  async createFromQuotation(ctx: ServiceContext, quotationId: string): Promise<SalesOrder | null> {
    const quotation = await this.quotationRepo.findOne({
      where: { id: quotationId, tenantId: ctx.tenantId },
    });

    if (!quotation) {
      return null;
    }

    if (quotation.status !== 'accepted') {
      throw new Error('Only accepted quotations can be converted to orders');
    }

    const quotationItems = await this.quotationItemRepo.find({
      where: { quotationId },
      order: { lineNumber: 'ASC' },
    });

    const order = await this.create(ctx, {
      quotationId,
      partnerId: quotation.partnerId,
      currencyId: quotation.currency,
      paymentTermId: undefined,
      notes: quotation.notes ?? undefined,
      termsConditions: quotation.termsAndConditions ?? undefined,
      items: quotationItems.map((item) => ({
        productId: item.productId,
        productSku: item.productSku,
        productName: item.productName,
        description: item.description,
        quantity: item.quantity,
        uom: item.uom,
        unitPrice: item.unitPrice,
        discountPercent: item.discountPercent,
        taxRate: item.taxRate,
      })),
    });

    quotation.status = 'converted';
    quotation.convertedToOrder = true;
    quotation.orderId = order.id;
    quotation.convertedAt = new Date();
    quotation.updatedBy = ctx.userId;

    await this.quotationRepo.save(quotation);

    return order;
  }

  async update(ctx: ServiceContext, id: string, dto: UpdateSalesOrderDto): Promise<SalesOrder | null> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return null;
    }

    if (order.status !== 'draft' && order.status !== 'sent') {
      throw new Error('Can only update draft or sent orders');
    }

    Object.assign(order, {
      ...dto,
      updatedBy: ctx.userId,
    });

    return this.orderRepo.save(order);
  }

  async addItem(ctx: ServiceContext, orderId: string, dto: CreateSalesOrderItemDto): Promise<SalesOrderItem | null> {
    const order = await this.findById(ctx, orderId);
    if (!order) {
      return null;
    }

    if (order.status !== 'draft' && order.status !== 'sent') {
      throw new Error('Can only add items to draft or sent orders');
    }

    return this.dataSource.transaction(async (manager) => {
      const itemRepo = manager.getRepository(SalesOrderItem);

      const lastItem = await itemRepo
        .createQueryBuilder('i')
        .where('i.order_id = :orderId', { orderId })
        .orderBy('i.line_number', 'DESC')
        .getOne();

      const lineNumber = (lastItem?.lineNumber ?? 0) + 1;
      const calculated = this.calculateItemTotals(dto);

      const item = itemRepo.create({
        orderId,
        lineNumber,
        productId: dto.productId,
        productSku: dto.productSku,
        productName: dto.productName,
        description: dto.description,
        quantity: dto.quantity,
        quantityReserved: 0,
        quantityShipped: 0,
        quantityDelivered: 0,
        quantityReturned: 0,
        uom: dto.uom ?? 'PZA',
        unitPrice: dto.unitPrice,
        unitCost: dto.unitCost ?? 0,
        discountPercent: dto.discountPercent ?? 0,
        taxRate: dto.taxRate ?? 16,
        lotNumber: dto.lotNumber,
        serialNumber: dto.serialNumber,
        status: 'pending',
        ...calculated,
      });

      const savedItem = await itemRepo.save(item);

      await this.recalculateOrderTotals(manager, orderId);

      return savedItem;
    });
  }

  async updateItem(
    ctx: ServiceContext,
    orderId: string,
    itemId: string,
    dto: UpdateSalesOrderItemDto,
  ): Promise<SalesOrderItem | null> {
    const order = await this.findById(ctx, orderId);
    if (!order) {
      return null;
    }

    if (order.status !== 'draft' && order.status !== 'sent') {
      throw new Error('Can only update items on draft or sent orders');
    }

    const item = await this.itemRepo.findOne({
      where: { id: itemId, orderId },
    });

    if (!item) {
      return null;
    }

    return this.dataSource.transaction(async (manager) => {
      const itemRepo = manager.getRepository(SalesOrderItem);

      Object.assign(item, dto);

      const calculated = this.calculateItemTotals({
        quantity: item.quantity,
        unitPrice: item.unitPrice,
        discountPercent: item.discountPercent,
        taxRate: item.taxRate,
        productName: item.productName,
      });

      Object.assign(item, calculated);

      const savedItem = await itemRepo.save(item);

      await this.recalculateOrderTotals(manager, orderId);

      return savedItem;
    });
  }

  async removeItem(ctx: ServiceContext, orderId: string, itemId: string): Promise<boolean> {
    const order = await this.findById(ctx, orderId);
    if (!order) {
      return false;
    }

    if (order.status !== 'draft' && order.status !== 'sent') {
      throw new Error('Can only remove items from draft or sent orders');
    }

    return this.dataSource.transaction(async (manager) => {
      const itemRepo = manager.getRepository(SalesOrderItem);

      const result = await itemRepo.delete({ id: itemId, orderId });
      if (!result.affected) {
        return false;
      }

      await this.recalculateOrderTotals(manager, orderId);

      return true;
    });
  }

  private async recalculateOrderTotals(
    manager: any,
    orderId: string,
  ): Promise<void> {
    const orderRepo = manager.getRepository(SalesOrder);
    const itemRepo = manager.getRepository(SalesOrderItem);

    const items = await itemRepo.find({
      where: { orderId },
    });

    const totals = this.calculateOrderTotals(items);

    await orderRepo.update({ id: orderId }, totals);
  }

  async confirm(ctx: ServiceContext, id: string): Promise<SalesOrder | null> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return null;
    }

    if (order.status !== 'draft' && order.status !== 'sent') {
      throw new Error('Can only confirm draft or sent orders');
    }

    order.status = 'sale';
    order.confirmedAt = new Date();
    order.confirmedBy = ctx.userId ?? null;
    order.updatedBy = ctx.userId ?? null;

    return this.orderRepo.save(order);
  }

  async send(ctx: ServiceContext, id: string): Promise<SalesOrder | null> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return null;
    }

    if (order.status !== 'draft') {
      throw new Error('Only draft orders can be sent');
    }

    order.status = 'sent';
    order.updatedBy = ctx.userId ?? null;

    return this.orderRepo.save(order);
  }

  async cancel(ctx: ServiceContext, id: string): Promise<SalesOrder | null> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return null;
    }

    if (order.status === 'done' || order.status === 'cancelled') {
      throw new Error('Cannot cancel a completed or already cancelled order');
    }

    if (order.deliveryStatus === 'delivered') {
      throw new Error('Cannot cancel an order that has been fully delivered');
    }

    if (order.invoiceStatus === 'invoiced') {
      throw new Error('Cannot cancel an order that has been fully invoiced');
    }

    order.status = 'cancelled';
    order.cancelledAt = new Date();
    order.cancelledBy = ctx.userId ?? null;
    order.updatedBy = ctx.userId ?? null;

    await this.itemRepo.update(
      { orderId: id },
      { status: 'cancelled' },
    );

    return this.orderRepo.save(order);
  }

  async markDone(ctx: ServiceContext, id: string): Promise<SalesOrder | null> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return null;
    }

    if (order.status !== 'sale') {
      throw new Error('Only confirmed orders can be marked as done');
    }

    order.status = 'done';
    order.updatedBy = ctx.userId ?? null;

    return this.orderRepo.save(order);
  }

  async updateDeliveryStatus(ctx: ServiceContext, id: string): Promise<SalesOrder | null> {
    const order = await this.findByIdWithItems(ctx, id);
    if (!order) {
      return null;
    }

    const items = (order as any).items as SalesOrderItem[];

    const totalQuantity = items.reduce((sum, item) => sum + Number(item.quantity), 0);
    const deliveredQuantity = items.reduce((sum, item) => sum + Number(item.quantityDelivered), 0);

    let deliveryStatus: 'pending' | 'partial' | 'delivered';
    if (deliveredQuantity === 0) {
      deliveryStatus = 'pending';
    } else if (deliveredQuantity >= totalQuantity) {
      deliveryStatus = 'delivered';
    } else {
      deliveryStatus = 'partial';
    }

    order.deliveryStatus = deliveryStatus;
    order.updatedBy = ctx.userId ?? null;

    return this.orderRepo.save(order);
  }

  async updateInvoiceStatus(ctx: ServiceContext, id: string, status: 'pending' | 'partial' | 'invoiced'): Promise<SalesOrder | null> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return null;
    }

    order.invoiceStatus = status;
    order.updatedBy = ctx.userId ?? null;

    return this.orderRepo.save(order);
  }

  async updateItemDelivery(
    ctx: ServiceContext,
    orderId: string,
    itemId: string,
    quantityDelivered: number,
  ): Promise<SalesOrderItem | null> {
    const item = await this.itemRepo.findOne({
      where: { id: itemId, orderId },
    });

    if (!item) {
      return null;
    }

    if (quantityDelivered > item.quantity) {
      throw new Error('Delivered quantity cannot exceed ordered quantity');
    }

    item.quantityDelivered = quantityDelivered;
    item.status = quantityDelivered >= item.quantity ? 'delivered' : 'shipped';

    const savedItem = await this.itemRepo.save(item);

    await this.updateDeliveryStatus(ctx, orderId);

    return savedItem;
  }

  async getStatistics(ctx: ServiceContext, dateFrom?: Date, dateTo?: Date): Promise<{
    totalOrders: number;
    draft: number;
    sent: number;
    confirmed: number;
    done: number;
    cancelled: number;
    totalRevenue: number;
    pendingDelivery: number;
    pendingInvoice: number;
    averageOrderValue: number;
  }> {
    const queryBuilder = this.orderRepo
      .createQueryBuilder('o')
      .where('o.tenant_id = :tenantId', { tenantId: ctx.tenantId })
      .andWhere('o.deleted_at IS NULL');

    if (dateFrom) {
      queryBuilder.andWhere('o.order_date >= :dateFrom', { dateFrom });
    }

    if (dateTo) {
      queryBuilder.andWhere('o.order_date <= :dateTo', { dateTo });
    }

    const orders = await queryBuilder.getMany();

    const draft = orders.filter((o) => o.status === 'draft');
    const sent = orders.filter((o) => o.status === 'sent');
    const confirmed = orders.filter((o) => o.status === 'sale');
    const done = orders.filter((o) => o.status === 'done');
    const cancelled = orders.filter((o) => o.status === 'cancelled');

    const activeOrders = orders.filter((o) => o.status !== 'cancelled' && o.status !== 'draft');
    const totalRevenue = activeOrders.reduce((sum, o) => sum + Number(o.amountTotal), 0);

    const pendingDelivery = orders.filter(
      (o) => o.status === 'sale' && (o.deliveryStatus === 'pending' || o.deliveryStatus === 'partial'),
    ).length;

    const pendingInvoice = orders.filter(
      (o) => o.status === 'sale' && (o.invoiceStatus === 'pending' || o.invoiceStatus === 'partial'),
    ).length;

    const averageOrderValue = activeOrders.length > 0
      ? totalRevenue / activeOrders.length
      : 0;

    return {
      totalOrders: orders.length,
      draft: draft.length,
      sent: sent.length,
      confirmed: confirmed.length,
      done: done.length,
      cancelled: cancelled.length,
      totalRevenue,
      pendingDelivery,
      pendingInvoice,
      averageOrderValue: Math.round(averageOrderValue * 100) / 100,
    };
  }

  async softDelete(ctx: ServiceContext, id: string): Promise<boolean> {
    const order = await this.findById(ctx, id);
    if (!order) {
      return false;
    }

    if (order.status === 'sale' || order.status === 'done') {
      throw new Error('Cannot delete confirmed or completed orders');
    }

    const result = await this.orderRepo.update(
      { id, tenantId: ctx.tenantId },
      { deletedAt: new Date(), updatedBy: ctx.userId },
    );

    return (result.affected ?? 0) > 0;
  }
}
