import { BadRequestException, Injectable } from '@nestjs/common';
import { CreateRendicionDto } from 'src/rendiciones/dto/rendiciones.dto';
import { RendicionesService } from 'src/rendiciones/rendiciones.service';
import { AbrirCajaDto } from 'src/tesoreria/dto/abrir-caja.dto';
import { CerrarCajaDto } from 'src/tesoreria/dto/cerrar-caja.dto';
import { TesoreriaService } from 'src/tesoreria/tesoreria.service';
import { VendedoresCobradoresService } from 'src/vendedores-cobradores/vendedores-cobradores.service';
import { RendirMobileDto } from './dto/rendir-mobile.dto';

/**
 * Caja del cobrador: compone los servicios existentes (Tesorería para
 * sesiones_caja y Rendiciones para la entrega), resolviendo el cobrador del
 * usuario para que el cliente móvil no tenga que conocerlo.
 */
@Injectable()
export class MobileCajaService {
  constructor(
    private readonly tesoreria: TesoreriaService,
    private readonly rendiciones: RendicionesService,
    private readonly vendedores: VendedoresCobradoresService,
  ) {}

  /** Cajas de la empresa con flag de sesión abierta (para la apertura). */
  disponibles(empresaId: string) {
    return this.tesoreria.getCajasDisponibles(empresaId);
  }

  /**
   * Sesión de caja abierta del propio cobrador (o null).
   *
   * `soloPropia` es obligatorio acá: sin él, un cobrador sin caja recibía la
   * sesión abierta de otro cajero y la app la mandaba como sesion_caja_id,
   * imputando el cobro a esa caja ajena.
   */
  actual(empresaId: string, usuarioId: string) {
    return this.tesoreria.getSesionActiva(empresaId, undefined, usuarioId, {
      soloPropia: true,
    });
  }

  abrir(dto: AbrirCajaDto, empresaId: string, usuarioId: string) {
    return this.tesoreria.abrirCaja(dto, empresaId, usuarioId);
  }

  cerrar(sesionId: string, dto: CerrarCajaDto, empresaId: string, usuarioId: string) {
    return this.tesoreria.cerrarCaja(sesionId, dto, empresaId, usuarioId);
  }

  private async cobradorIdOrThrow(empresaId: string, usuarioId: string): Promise<string> {
    const cobrador = await this.vendedores.findCobradorVinculado(empresaId, usuarioId);
    if (!cobrador) {
      const diag = await this.vendedores.diagnosticarVinculoCobrador(empresaId, usuarioId);
      throw new BadRequestException(diag.mensaje ?? 'No podés rendir.');
    }
    return cobrador.id;
  }

  /** Recibos del cobrador aún no rendidos (para armar la rendición). */
  async recibosDisponibles(empresaId: string, usuarioId: string, fecha?: string, monedaId?: string) {
    const cobradorId = await this.cobradorIdOrThrow(empresaId, usuarioId);
    return this.rendiciones.getRecibosDisponibles(empresaId, cobradorId, fecha, monedaId);
  }

  /**
   * Crea la rendición del día y la envía directo a tesorería (PENDIENTE).
   * El cobrador móvil no tiene web para promover BORRADOR→PENDIENTE, así que
   * encadenamos las dos operaciones acá.
   */
  async rendir(empresaId: string, usuarioId: string, dto: RendirMobileDto) {
    const cobradorId = await this.cobradorIdOrThrow(empresaId, usuarioId);
    const payload: CreateRendicionDto = {
      cobrador_id: cobradorId,
      fecha_cobranza: new Date().toISOString().slice(0, 10),
      moneda_id: dto.moneda_id,
      recibo_ids: dto.recibo_ids,
      total_declarado: dto.total_declarado,
      observaciones_cobrador: dto.observaciones,
    };
    const creada: any = await this.rendiciones.create(empresaId, usuarioId, payload);
    await this.rendiciones.enviarATesoreria(empresaId, creada.id, usuarioId, {
      total_declarado: dto.total_declarado,
      observaciones_cobrador: dto.observaciones,
    });
    return this.rendiciones.findOne(empresaId, creada.id);
  }
}
