import {
  Repository,
  FindOptionsWhere,
  ILike,
  In,
  LessThan,
  LessThanOrEqual,
  MoreThanOrEqual,
  Between,
} from 'typeorm';
import {
  FacturaTransporte,
  EstadoFactura,
  LineaFactura,
  RecargoCatalogo,
} from '../entities';

// =====================================================
// DTOs
// =====================================================

export interface CreateFacturaDto {
  serie?: string;
  folio: string;
  clienteId: string;
  clienteRfc: string;
  clienteRazonSocial: string;
  clienteUsoCfdi?: string;
  fechaEmision: Date;
  fechaVencimiento?: Date;
  formaPago?: string;
  metodoPago?: string;
  condicionesPago?: string;
  moneda?: string;
  tipoCambio?: number;
  viajeIds?: string[];
  otIds?: string[];
}

export interface UpdateFacturaDto {
  serie?: string;
  clienteUsoCfdi?: string;
  fechaVencimiento?: Date;
  formaPago?: string;
  metodoPago?: string;
  condicionesPago?: string;
  moneda?: string;
  tipoCambio?: number;
}

export interface CreateLineaFacturaDto {
  descripcion: string;
  claveProductoSat?: string;
  unidadSat?: string;
  cantidad: number;
  precioUnitario: number;
  descuento?: number;
  ivaTasa?: number;
  viajeId?: string;
  otId?: string;
  recargoId?: string;
}

export interface FacturaSearchParams {
  tenantId: string;
  search?: string;
  clienteId?: string;
  estado?: EstadoFactura;
  fechaDesde?: Date;
  fechaHasta?: Date;
  moneda?: string;
  limit?: number;
  offset?: number;
}

export interface RecargoAplicarDto {
  recargoId: string;
  descripcion?: string;
  monto?: number;
  cantidad?: number;
}

export interface DescuentoAplicarDto {
  descripcion: string;
  porcentaje?: number;
  montoFijo?: number;
  lineaIds?: string[];
}

export interface EstadoCuentaItem {
  facturaId: string;
  folioCompleto: string;
  fechaEmision: Date;
  fechaVencimiento: Date | null;
  total: number;
  montoPagado: number;
  saldoPendiente: number;
  diasVencida: number;
  estado: EstadoFactura;
}

export interface EstadoCuentaResult {
  clienteId: string;
  clienteRazonSocial: string;
  facturas: EstadoCuentaItem[];
  totalFacturado: number;
  totalPagado: number;
  saldoTotal: number;
  facturasVencidas: number;
  montoVencido: number;
}

// =====================================================
// Constants
// =====================================================

const IVA_TASA_DEFAULT = 16; // 16% IVA Mexico

// =====================================================
// Service
// =====================================================

export class FacturaTransporteService {
  constructor(
    private readonly facturaRepository: Repository<FacturaTransporte>,
    private readonly lineaRepository: Repository<LineaFactura>,
    private readonly recargoRepository: Repository<RecargoCatalogo>
  ) {}

  // ---------------------------------------------------------------------------
  // CRUD Operations
  // ---------------------------------------------------------------------------

  /**
   * Create a new transport invoice
   */
  async create(
    tenantId: string,
    dto: CreateFacturaDto,
    createdBy: string
  ): Promise<FacturaTransporte> {
    // Check if folio already exists for this series
    const existingFolio = await this.facturaRepository.findOne({
      where: {
        tenantId,
        ...(dto.serie ? { serie: dto.serie } : {}),
        folio: dto.folio,
      },
    });

    if (existingFolio) {
      throw new Error(
        `Ya existe una factura con el folio "${dto.serie ? dto.serie + '-' : ''}${dto.folio}"`
      );
    }

    const factura = this.facturaRepository.create({
      tenantId,
      serie: dto.serie ?? null,
      folio: dto.folio,
      clienteId: dto.clienteId,
      clienteRfc: dto.clienteRfc,
      clienteRazonSocial: dto.clienteRazonSocial,
      clienteUsoCfdi: dto.clienteUsoCfdi ?? null,
      fechaEmision: dto.fechaEmision,
      fechaVencimiento: dto.fechaVencimiento ?? null,
      formaPago: dto.formaPago ?? null,
      metodoPago: dto.metodoPago ?? null,
      condicionesPago: dto.condicionesPago ?? null,
      moneda: dto.moneda ?? 'MXN',
      tipoCambio: dto.tipoCambio ?? 1,
      viajeIds: dto.viajeIds ?? null,
      otIds: dto.otIds ?? null,
      subtotal: 0,
      descuento: 0,
      iva: 0,
      retencionIva: 0,
      retencionIsr: 0,
      total: 0,
      estado: EstadoFactura.BORRADOR,
      montoPagado: 0,
      createdById: createdBy,
    });

    return this.facturaRepository.save(factura);
  }

  /**
   * Find invoice by ID
   */
  async findById(tenantId: string, id: string): Promise<FacturaTransporte | null> {
    return this.facturaRepository.findOne({
      where: { id, tenantId },
      relations: ['lineas'],
    });
  }

  /**
   * Find all invoices with filters
   */
  async findAll(
    params: FacturaSearchParams
  ): Promise<{ data: FacturaTransporte[]; total: number }> {
    const {
      tenantId,
      search,
      clienteId,
      estado,
      fechaDesde,
      fechaHasta,
      moneda,
      limit = 50,
      offset = 0,
    } = params;

    const qb = this.facturaRepository.createQueryBuilder('f');

    qb.where('f.tenant_id = :tenantId', { tenantId });

    if (clienteId) {
      qb.andWhere('f.cliente_id = :clienteId', { clienteId });
    }

    if (estado) {
      qb.andWhere('f.estado = :estado', { estado });
    }

    if (fechaDesde) {
      qb.andWhere('f.fecha_emision >= :fechaDesde', { fechaDesde });
    }

    if (fechaHasta) {
      qb.andWhere('f.fecha_emision <= :fechaHasta', { fechaHasta });
    }

    if (moneda) {
      qb.andWhere('f.moneda = :moneda', { moneda });
    }

    if (search) {
      qb.andWhere(
        '(f.folio ILIKE :search OR f.cliente_razon_social ILIKE :search OR f.cliente_rfc ILIKE :search)',
        { search: `%${search}%` }
      );
    }

    qb.leftJoinAndSelect('f.lineas', 'lineas');
    qb.orderBy('f.fecha_emision', 'DESC');
    qb.addOrderBy('f.folio', 'DESC');
    qb.take(limit);
    qb.skip(offset);

    const [data, total] = await qb.getManyAndCount();

    return { data, total };
  }

  /**
   * Find invoices by client
   */
  async findByCliente(
    tenantId: string,
    clienteId: string,
    limit: number = 50,
    offset: number = 0
  ): Promise<{ data: FacturaTransporte[]; total: number }> {
    const [data, total] = await this.facturaRepository.findAndCount({
      where: { tenantId, clienteId },
      relations: ['lineas'],
      order: { fechaEmision: 'DESC' },
      take: limit,
      skip: offset,
    });

    return { data, total };
  }

  /**
   * Find invoices by status
   */
  async findByEstado(
    tenantId: string,
    estado: EstadoFactura,
    limit: number = 50,
    offset: number = 0
  ): Promise<{ data: FacturaTransporte[]; total: number }> {
    const [data, total] = await this.facturaRepository.findAndCount({
      where: { tenantId, estado },
      relations: ['lineas'],
      order: { fechaEmision: 'DESC' },
      take: limit,
      skip: offset,
    });

    return { data, total };
  }

  /**
   * Update invoice (only if in BORRADOR state)
   */
  async update(
    tenantId: string,
    id: string,
    dto: UpdateFacturaDto
  ): Promise<FacturaTransporte | null> {
    const factura = await this.findById(tenantId, id);
    if (!factura) return null;

    if (factura.estado !== EstadoFactura.BORRADOR) {
      throw new Error('Solo se pueden modificar facturas en estado BORRADOR');
    }

    Object.assign(factura, {
      serie: dto.serie !== undefined ? dto.serie : factura.serie,
      clienteUsoCfdi:
        dto.clienteUsoCfdi !== undefined ? dto.clienteUsoCfdi : factura.clienteUsoCfdi,
      fechaVencimiento:
        dto.fechaVencimiento !== undefined ? dto.fechaVencimiento : factura.fechaVencimiento,
      formaPago: dto.formaPago !== undefined ? dto.formaPago : factura.formaPago,
      metodoPago: dto.metodoPago !== undefined ? dto.metodoPago : factura.metodoPago,
      condicionesPago:
        dto.condicionesPago !== undefined ? dto.condicionesPago : factura.condicionesPago,
      moneda: dto.moneda !== undefined ? dto.moneda : factura.moneda,
      tipoCambio: dto.tipoCambio !== undefined ? dto.tipoCambio : factura.tipoCambio,
    });

    return this.facturaRepository.save(factura);
  }

  // ---------------------------------------------------------------------------
  // Line Items Management
  // ---------------------------------------------------------------------------

  /**
   * Add line item to invoice
   */
  async addLinea(
    tenantId: string,
    facturaId: string,
    lineaData: CreateLineaFacturaDto
  ): Promise<LineaFactura> {
    const factura = await this.findById(tenantId, facturaId);
    if (!factura) {
      throw new Error('Factura no encontrada');
    }

    if (factura.estado !== EstadoFactura.BORRADOR) {
      throw new Error('Solo se pueden agregar lineas a facturas en estado BORRADOR');
    }

    // Get next line number
    const maxLinea = await this.lineaRepository
      .createQueryBuilder('l')
      .select('MAX(l.linea)', 'max')
      .where('l.factura_id = :facturaId', { facturaId })
      .getRawOne();

    const lineaNumero = (maxLinea?.max ?? 0) + 1;

    // Calculate importe
    const importe = lineaData.cantidad * lineaData.precioUnitario;
    const ivaTasa = lineaData.ivaTasa ?? IVA_TASA_DEFAULT;
    const descuento = lineaData.descuento ?? 0;
    const importeNeto = importe - descuento;
    const ivaMonto = importeNeto * (ivaTasa / 100);

    const linea = this.lineaRepository.create({
      tenantId,
      facturaId,
      linea: lineaNumero,
      descripcion: lineaData.descripcion,
      claveProductoSat: lineaData.claveProductoSat ?? null,
      unidadSat: lineaData.unidadSat ?? null,
      cantidad: lineaData.cantidad,
      precioUnitario: lineaData.precioUnitario,
      descuento,
      importe,
      ivaTasa,
      ivaMonto,
      viajeId: lineaData.viajeId ?? null,
      otId: lineaData.otId ?? null,
      recargoId: lineaData.recargoId ?? null,
    });

    const savedLinea = await this.lineaRepository.save(linea);

    // Recalculate totals
    await this.calculateTotals(tenantId, facturaId);

    return savedLinea;
  }

  /**
   * Remove line item from invoice
   */
  async removeLinea(
    tenantId: string,
    facturaId: string,
    lineaId: string
  ): Promise<boolean> {
    const factura = await this.findById(tenantId, facturaId);
    if (!factura) {
      throw new Error('Factura no encontrada');
    }

    if (factura.estado !== EstadoFactura.BORRADOR) {
      throw new Error('Solo se pueden eliminar lineas de facturas en estado BORRADOR');
    }

    const linea = await this.lineaRepository.findOne({
      where: { id: lineaId, facturaId, tenantId },
    });

    if (!linea) {
      return false;
    }

    await this.lineaRepository.delete(lineaId);

    // Renumber remaining lines
    const remainingLineas = await this.lineaRepository.find({
      where: { facturaId },
      order: { linea: 'ASC' },
    });

    for (let i = 0; i < remainingLineas.length; i++) {
      if (remainingLineas[i].linea !== i + 1) {
        remainingLineas[i].linea = i + 1;
        await this.lineaRepository.save(remainingLineas[i]);
      }
    }

    // Recalculate totals
    await this.calculateTotals(tenantId, facturaId);

    return true;
  }

  // ---------------------------------------------------------------------------
  // Calculations
  // ---------------------------------------------------------------------------

  /**
   * Recalculate invoice totals (subtotal, IVA 16%, total)
   */
  async calculateTotals(tenantId: string, id: string): Promise<FacturaTransporte | null> {
    const factura = await this.facturaRepository.findOne({
      where: { id, tenantId },
      relations: ['lineas'],
    });

    if (!factura) return null;

    const lineas = factura.lineas ?? [];

    let subtotal = 0;
    let descuentoTotal = 0;
    let ivaTotal = 0;

    for (const linea of lineas) {
      subtotal += Number(linea.importe);
      descuentoTotal += Number(linea.descuento);
      ivaTotal += Number(linea.ivaMonto ?? 0);
    }

    factura.subtotal = subtotal;
    factura.descuento = descuentoTotal;
    factura.iva = ivaTotal;
    factura.total = subtotal - descuentoTotal + ivaTotal - factura.retencionIva - factura.retencionIsr;

    return this.facturaRepository.save(factura);
  }

  /**
   * Apply surcharges to invoice
   */
  async applyRecargos(
    tenantId: string,
    id: string,
    recargos: RecargoAplicarDto[]
  ): Promise<FacturaTransporte | null> {
    const factura = await this.findById(tenantId, id);
    if (!factura) {
      throw new Error('Factura no encontrada');
    }

    if (factura.estado !== EstadoFactura.BORRADOR) {
      throw new Error('Solo se pueden aplicar recargos a facturas en estado BORRADOR');
    }

    for (const recargoDto of recargos) {
      const recargo = await this.recargoRepository.findOne({
        where: { id: recargoDto.recargoId, tenantId, activo: true },
      });

      if (!recargo) {
        throw new Error(`Recargo no encontrado: ${recargoDto.recargoId}`);
      }

      // Calculate surcharge amount
      let montoRecargo = recargoDto.monto;
      if (montoRecargo === undefined) {
        if (recargo.esPorcentaje) {
          montoRecargo = factura.subtotal * (Number(recargo.monto) / 100);
        } else {
          montoRecargo = Number(recargo.monto);
        }
      }

      const cantidad = recargoDto.cantidad ?? 1;

      await this.addLinea(tenantId, id, {
        descripcion: recargoDto.descripcion ?? `${recargo.nombre}`,
        claveProductoSat: '78101800', // SAT code for transport services
        unidadSat: 'E48', // Unit of service
        cantidad,
        precioUnitario: montoRecargo,
        ivaTasa: IVA_TASA_DEFAULT,
        recargoId: recargo.id,
      });
    }

    return this.findById(tenantId, id);
  }

  /**
   * Apply discounts to invoice
   */
  async applyDescuentos(
    tenantId: string,
    id: string,
    descuentos: DescuentoAplicarDto[]
  ): Promise<FacturaTransporte | null> {
    const factura = await this.findById(tenantId, id);
    if (!factura) {
      throw new Error('Factura no encontrada');
    }

    if (factura.estado !== EstadoFactura.BORRADOR) {
      throw new Error('Solo se pueden aplicar descuentos a facturas en estado BORRADOR');
    }

    const lineas = factura.lineas ?? [];

    for (const descuentoDto of descuentos) {
      // Determine which lines to apply discount to
      const targetLineas = descuentoDto.lineaIds
        ? lineas.filter((l) => descuentoDto.lineaIds!.includes(l.id))
        : lineas.filter((l) => !l.recargoId); // Exclude surcharge lines by default

      if (targetLineas.length === 0) continue;

      for (const linea of targetLineas) {
        let descuentoMonto = 0;

        if (descuentoDto.porcentaje) {
          descuentoMonto = Number(linea.importe) * (descuentoDto.porcentaje / 100);
        } else if (descuentoDto.montoFijo) {
          // Distribute fixed amount proportionally
          const totalImporte = targetLineas.reduce(
            (sum, l) => sum + Number(l.importe),
            0
          );
          const proportion = Number(linea.importe) / totalImporte;
          descuentoMonto = descuentoDto.montoFijo * proportion;
        }

        linea.descuento = Number(linea.descuento) + descuentoMonto;

        // Recalculate IVA
        const importeNeto = Number(linea.importe) - Number(linea.descuento);
        linea.ivaMonto = importeNeto * (Number(linea.ivaTasa) / 100);

        await this.lineaRepository.save(linea);
      }
    }

    // Recalculate totals
    return this.calculateTotals(tenantId, id);
  }

  // ---------------------------------------------------------------------------
  // Status Management
  // ---------------------------------------------------------------------------

  /**
   * Mark invoice as sent to SAT (CFDI timbrado)
   */
  async timbrar(
    tenantId: string,
    id: string,
    cfdiData: { uuidCfdi: string; xmlCfdi: string; pdfUrl?: string }
  ): Promise<FacturaTransporte | null> {
    const factura = await this.findById(tenantId, id);
    if (!factura) {
      throw new Error('Factura no encontrada');
    }

    if (factura.estado !== EstadoFactura.BORRADOR && factura.estado !== EstadoFactura.EMITIDA) {
      throw new Error('Solo se pueden timbrar facturas en estado BORRADOR o EMITIDA');
    }

    // Validate invoice has lines
    const lineas = factura.lineas ?? [];
    if (lineas.length === 0) {
      throw new Error('La factura debe tener al menos una linea para timbrar');
    }

    // Validate totals are correct
    if (factura.total <= 0) {
      throw new Error('El total de la factura debe ser mayor a cero');
    }

    factura.uuidCfdi = cfdiData.uuidCfdi;
    factura.xmlCfdi = cfdiData.xmlCfdi;
    factura.pdfUrl = cfdiData.pdfUrl ?? null;
    factura.estado = EstadoFactura.EMITIDA;

    return this.facturaRepository.save(factura);
  }

  /**
   * Cancel invoice
   */
  async cancelar(
    tenantId: string,
    id: string,
    motivo: string
  ): Promise<FacturaTransporte | null> {
    const factura = await this.findById(tenantId, id);
    if (!factura) {
      throw new Error('Factura no encontrada');
    }

    if (factura.estado === EstadoFactura.CANCELADA) {
      throw new Error('La factura ya esta cancelada');
    }

    if (factura.estado === EstadoFactura.PAGADA) {
      throw new Error('No se puede cancelar una factura que ya fue pagada completamente');
    }

    factura.estado = EstadoFactura.CANCELADA;
    factura.fechaCancelacion = new Date();
    factura.motivoCancelacion = motivo;

    return this.facturaRepository.save(factura);
  }

  // ---------------------------------------------------------------------------
  // Account Statements & Reports
  // ---------------------------------------------------------------------------

  /**
   * Get client account statement
   */
  async getEstadoCuenta(
    tenantId: string,
    clienteId: string
  ): Promise<EstadoCuentaResult> {
    const facturas = await this.facturaRepository.find({
      where: {
        tenantId,
        clienteId,
        estado: In([
          EstadoFactura.EMITIDA,
          EstadoFactura.ENVIADA,
          EstadoFactura.PARCIAL,
          EstadoFactura.VENCIDA,
          EstadoFactura.PAGADA,
        ]),
      },
      order: { fechaEmision: 'DESC' },
    });

    if (facturas.length === 0) {
      return {
        clienteId,
        clienteRazonSocial: '',
        facturas: [],
        totalFacturado: 0,
        totalPagado: 0,
        saldoTotal: 0,
        facturasVencidas: 0,
        montoVencido: 0,
      };
    }

    const clienteRazonSocial = facturas[0].clienteRazonSocial;
    const hoy = new Date();

    let totalFacturado = 0;
    let totalPagado = 0;
    let saldoTotal = 0;
    let facturasVencidas = 0;
    let montoVencido = 0;

    const items: EstadoCuentaItem[] = facturas.map((f) => {
      const total = Number(f.total);
      const montoPagado = Number(f.montoPagado);
      const saldoPendiente = total - montoPagado;

      totalFacturado += total;
      totalPagado += montoPagado;
      saldoTotal += saldoPendiente;

      let diasVencida = 0;
      if (f.fechaVencimiento && saldoPendiente > 0) {
        const vencimiento = new Date(f.fechaVencimiento);
        if (hoy > vencimiento) {
          diasVencida = Math.ceil(
            (hoy.getTime() - vencimiento.getTime()) / (1000 * 60 * 60 * 24)
          );
          facturasVencidas++;
          montoVencido += saldoPendiente;
        }
      }

      return {
        facturaId: f.id,
        folioCompleto: f.folioCompleto,
        fechaEmision: f.fechaEmision,
        fechaVencimiento: f.fechaVencimiento,
        total,
        montoPagado,
        saldoPendiente,
        diasVencida,
        estado: f.estado,
      };
    });

    return {
      clienteId,
      clienteRazonSocial,
      facturas: items,
      totalFacturado,
      totalPagado,
      saldoTotal,
      facturasVencidas,
      montoVencido,
    };
  }

  /**
   * Get pending invoices (emitted but not fully paid)
   */
  async getFacturasPendientes(
    tenantId: string,
    limit: number = 100,
    offset: number = 0
  ): Promise<{ data: FacturaTransporte[]; total: number }> {
    const [data, total] = await this.facturaRepository.findAndCount({
      where: {
        tenantId,
        estado: In([
          EstadoFactura.EMITIDA,
          EstadoFactura.ENVIADA,
          EstadoFactura.PARCIAL,
          EstadoFactura.VENCIDA,
        ]),
      },
      relations: ['lineas'],
      order: { fechaEmision: 'ASC' },
      take: limit,
      skip: offset,
    });

    return { data, total };
  }

  /**
   * Get overdue invoices
   */
  async getFacturasVencidas(
    tenantId: string,
    diasVencidas?: number,
    limit: number = 100,
    offset: number = 0
  ): Promise<{ data: FacturaTransporte[]; total: number; montoTotal: number }> {
    const hoy = new Date();
    let fechaLimite = hoy;

    if (diasVencidas !== undefined) {
      fechaLimite = new Date();
      fechaLimite.setDate(fechaLimite.getDate() - diasVencidas);
    }

    const qb = this.facturaRepository.createQueryBuilder('f');

    qb.where('f.tenant_id = :tenantId', { tenantId });
    qb.andWhere('f.estado IN (:...estados)', {
      estados: [EstadoFactura.EMITIDA, EstadoFactura.ENVIADA, EstadoFactura.PARCIAL, EstadoFactura.VENCIDA],
    });
    qb.andWhere('f.fecha_vencimiento IS NOT NULL');
    qb.andWhere('f.fecha_vencimiento < :hoy', { hoy });

    if (diasVencidas !== undefined) {
      qb.andWhere('f.fecha_vencimiento <= :fechaLimite', { fechaLimite });
    }

    qb.leftJoinAndSelect('f.lineas', 'lineas');
    qb.orderBy('f.fecha_vencimiento', 'ASC');
    qb.take(limit);
    qb.skip(offset);

    const [data, total] = await qb.getManyAndCount();

    const montoTotal = data.reduce(
      (sum, f) => sum + (Number(f.total) - Number(f.montoPagado)),
      0
    );

    return { data, total, montoTotal };
  }

  // ---------------------------------------------------------------------------
  // Payment Registration
  // ---------------------------------------------------------------------------

  /**
   * Register payment for invoice
   */
  async registrarPago(
    tenantId: string,
    id: string,
    montoPago: number,
    fechaPago: Date = new Date()
  ): Promise<FacturaTransporte | null> {
    const factura = await this.findById(tenantId, id);
    if (!factura) {
      throw new Error('Factura no encontrada');
    }

    if (factura.estado === EstadoFactura.CANCELADA) {
      throw new Error('No se pueden registrar pagos en facturas canceladas');
    }

    if (factura.estado === EstadoFactura.BORRADOR) {
      throw new Error('La factura debe estar emitida para registrar pagos');
    }

    const nuevoMontoPagado = Number(factura.montoPagado) + montoPago;
    const total = Number(factura.total);

    if (nuevoMontoPagado > total) {
      throw new Error(
        `El monto de pago ($${montoPago}) excede el saldo pendiente ($${total - Number(factura.montoPagado)})`
      );
    }

    factura.montoPagado = nuevoMontoPagado;
    factura.fechaPago = fechaPago;

    // Update status based on payment
    if (nuevoMontoPagado >= total) {
      factura.estado = EstadoFactura.PAGADA;
    } else if (nuevoMontoPagado > 0) {
      factura.estado = EstadoFactura.PARCIAL;
    }

    return this.facturaRepository.save(factura);
  }

  // ---------------------------------------------------------------------------
  // Utility Methods
  // ---------------------------------------------------------------------------

  /**
   * Generate next folio number for a series
   */
  async generateNextFolio(tenantId: string, serie?: string): Promise<string> {
    const lastFactura = await this.facturaRepository.findOne({
      where: {
        tenantId,
        serie: serie ?? null as unknown as string,
      },
      order: { folio: 'DESC' },
    });

    if (!lastFactura) {
      return '1';
    }

    // Try to parse as number and increment
    const lastNumber = parseInt(lastFactura.folio, 10);
    if (!isNaN(lastNumber)) {
      return String(lastNumber + 1).padStart(lastFactura.folio.length, '0');
    }

    // If not a number, append timestamp
    return `${Date.now()}`;
  }

  /**
   * Get invoice summary for a period
   */
  async getResumenPeriodo(
    tenantId: string,
    fechaDesde: Date,
    fechaHasta: Date
  ): Promise<{
    totalFacturado: number;
    totalCobrado: number;
    totalPendiente: number;
    totalCancelado: number;
    cantidadFacturas: number;
    cantidadPagadas: number;
    cantidadPendientes: number;
    cantidadCanceladas: number;
  }> {
    const facturas = await this.facturaRepository.find({
      where: {
        tenantId,
        fechaEmision: Between(fechaDesde, fechaHasta),
      },
    });

    let totalFacturado = 0;
    let totalCobrado = 0;
    let totalPendiente = 0;
    let totalCancelado = 0;
    let cantidadPagadas = 0;
    let cantidadPendientes = 0;
    let cantidadCanceladas = 0;

    for (const f of facturas) {
      const total = Number(f.total);
      const pagado = Number(f.montoPagado);

      if (f.estado === EstadoFactura.CANCELADA) {
        totalCancelado += total;
        cantidadCanceladas++;
      } else {
        totalFacturado += total;
        totalCobrado += pagado;
        totalPendiente += total - pagado;

        if (f.estado === EstadoFactura.PAGADA) {
          cantidadPagadas++;
        } else {
          cantidadPendientes++;
        }
      }
    }

    return {
      totalFacturado,
      totalCobrado,
      totalPendiente,
      totalCancelado,
      cantidadFacturas: facturas.length,
      cantidadPagadas,
      cantidadPendientes,
      cantidadCanceladas,
    };
  }
}
