import { BadRequestException, Injectable } from '@nestjs/common';
import { RendicionesService } from 'src/rendiciones/rendiciones.service';
import { VendedoresCobradoresService } from 'src/vendedores-cobradores/vendedores-cobradores.service';

/**
 * MobileRendicionesService
 * ─────────────────────────────────────────────────────────────────────
 * Capa delgada de presentación: reutiliza por DI el RendicionesService de
 * dominio. Aplica scope al cobrador vinculado al usuario logueado (nunca
 * expone rendiciones de otros cobradores) y mapea los estados al lenguaje
 * humano que la app usa en los chips (`estado_label`, `estado_color`).
 */

type EstadoRendicion = 'BORRADOR' | 'PENDIENTE' | 'APROBADO' | 'OBSERVADO' | 'RECHAZADO';

interface EstadoView {
  estado: EstadoRendicion;
  estado_label: string;   // texto para la pantalla (en español, sin jerga técnica)
  estado_emoji: string;   // ícono visual coherente con `i18n/icons.ts`
  estado_color: 'default' | 'info' | 'warning' | 'success' | 'error';
  puede_reenviar: boolean; // BORRADOR / OBSERVADO
  resuelto: boolean;       // APROBADO o RECHAZADO finalizan el ciclo
}

function decorarEstado(estado: string | null | undefined): EstadoView {
  const e = (estado ?? 'BORRADOR') as EstadoRendicion;
  switch (e) {
    case 'BORRADOR':
      return {
        estado: e,
        estado_label: 'Sin enviar',
        estado_emoji: '✏️',
        estado_color: 'default',
        puede_reenviar: true,
        resuelto: false,
      };
    case 'PENDIENTE':
      return {
        estado: e,
        estado_label: 'Esperando aprobación',
        estado_emoji: '⏳',
        estado_color: 'info',
        puede_reenviar: false,
        resuelto: false,
      };
    case 'OBSERVADO':
      return {
        estado: e,
        estado_label: 'La tesorería pidió aclarar algo',
        estado_emoji: '⚠️',
        estado_color: 'warning',
        puede_reenviar: true,
        resuelto: false,
      };
    case 'APROBADO':
      return {
        estado: e,
        estado_label: 'Aprobada',
        estado_emoji: '✅',
        estado_color: 'success',
        puede_reenviar: false,
        resuelto: true,
      };
    case 'RECHAZADO':
      return {
        estado: e,
        estado_label: 'Rechazada',
        estado_emoji: '❌',
        estado_color: 'error',
        puede_reenviar: false,
        resuelto: true,
      };
    default:
      return {
        estado: 'BORRADOR',
        estado_label: 'Sin enviar',
        estado_emoji: '✏️',
        estado_color: 'default',
        puede_reenviar: true,
        resuelto: false,
      };
  }
}

@Injectable()
export class MobileRendicionesService {
  constructor(
    private readonly rendiciones: RendicionesService,
    private readonly vendedores: VendedoresCobradoresService,
  ) {}

  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 ver rendiciones.');
    }
    return cobrador.id;
  }

  async listarMisRendiciones(
    empresaId: string,
    usuarioId: string,
    query: { estado?: string; fecha_desde?: string; fecha_hasta?: string; page?: number; limit?: number },
  ) {
    const cobradorId = await this.cobradorIdOrThrow(empresaId, usuarioId);
    const res = await this.rendiciones.findAll(empresaId, {
      cobrador_id: cobradorId,
      estado: query.estado,
      fecha_desde: query.fecha_desde,
      fecha_hasta: query.fecha_hasta,
      page: query.page ?? 1,
      limit: query.limit ?? 20,
    });

    const data = (res.data as any[]).map((r) => {
      const v = decorarEstado(r.estado);
      return {
        id: r.id,
        numero: r.numero_rendicion ?? r.numero ?? null,
        fecha_rendicion: r.fecha_rendicion,
        fecha_cobranza: r.fecha_cobranza,
        total_declarado: Number(r.total_declarado ?? 0),
        total_recibos: Number(r.total_recibos ?? r.total_sistema ?? 0),
        cantidad_recibos: r._count?.recibos_cobro ?? 0,
        moneda: r.moneda ? { codigo: r.moneda.codigo, simbolo: r.moneda.simbolo } : null,
        observacion_tesoreria: r.observacion_tesoreria ?? r.motivo_rechazo ?? null,
        ...v,
      };
    });

    return { data, total: res.total, page: res.page, limit: res.limit, totalPages: res.totalPages };
  }

  async detalle(empresaId: string, usuarioId: string, id: string) {
    const cobradorId = await this.cobradorIdOrThrow(empresaId, usuarioId);
    const r: any = await this.rendiciones.findOne(empresaId, id);

    if (r.cobrador_id && r.cobrador_id !== cobradorId) {
      throw new BadRequestException('Esta rendición no es tuya.');
    }

    const v = decorarEstado(r.estado);
    return {
      id: r.id,
      numero: r.numero_rendicion ?? r.numero ?? null,
      fecha_rendicion: r.fecha_rendicion,
      fecha_cobranza: r.fecha_cobranza,
      total_declarado: Number(r.total_declarado ?? 0),
      total_recibos: Number(r.total_recibos ?? r.total_sistema ?? 0),
      cantidad_recibos: Array.isArray(r.recibos_cobro) ? r.recibos_cobro.length : (r._count?.recibos_cobro ?? 0),
      moneda: r.moneda ? { codigo: r.moneda.codigo, simbolo: r.moneda.simbolo } : null,
      observacion_tesoreria: r.observacion_tesoreria ?? r.motivo_rechazo ?? null,
      recibos: Array.isArray(r.recibos_cobro)
        ? r.recibos_cobro.map((rc: any) => ({
            id: rc.id,
            numero_recibo: rc.numero_recibo,
            fecha_emision: rc.fecha_emision,
            monto_total: Number(rc.monto_total ?? 0),
            cliente_razon_social:
              rc.clientes?.personas?.razon_social ?? rc.clientes?.nombre_fantasia ?? null,
          }))
        : [],
      historial: Array.isArray(r.historial)
        ? r.historial.map((h: any) => ({
            fecha: h.created_at ?? h.fecha,
            estado_anterior: h.estado_anterior ?? null,
            estado_nuevo: h.estado_nuevo,
            motivo: h.motivo ?? h.observacion ?? null,
            usuario_nombre:
              h.usuario?.nombres || h.usuario?.apellidos
                ? `${h.usuario?.nombres ?? ''} ${h.usuario?.apellidos ?? ''}`.trim()
                : null,
          }))
        : [],
      ...v,
    };
  }

  /**
   * KPIs para el badge del Home: cuántas rendiciones esperan aprobación,
   * cuántas observadas, cuánto rendido en el mes corriente.
   */
  async resumenCobrador(empresaId: string, usuarioId: string) {
    const cobradorId = await this.cobradorIdOrThrow(empresaId, usuarioId);

    const hoy = new Date();
    const inicioMes = new Date(hoy.getFullYear(), hoy.getMonth(), 1)
      .toISOString()
      .slice(0, 10);
    const finMes = hoy.toISOString().slice(0, 10);

    const [pendientes, observadas, mesActual] = await Promise.all([
      this.rendiciones.findAll(empresaId, { cobrador_id: cobradorId, estado: 'PENDIENTE', page: 1, limit: 1 }),
      this.rendiciones.findAll(empresaId, { cobrador_id: cobradorId, estado: 'OBSERVADO', page: 1, limit: 1 }),
      this.rendiciones.findAll(empresaId, {
        cobrador_id: cobradorId,
        estado: 'APROBADO',
        fecha_desde: inicioMes,
        fecha_hasta: finMes,
        page: 1,
        limit: 100,
      }),
    ]);

    const totalAprobadoMes = (mesActual.data as any[]).reduce(
      (acc, r) => acc + Number(r.total_declarado ?? 0),
      0,
    );

    return {
      pendientes_aprobacion: pendientes.total,
      observadas: observadas.total,
      aprobadas_mes: mesActual.total,
      total_aprobado_mes: totalAprobadoMes,
    };
  }

  /**
   * Recibos sin rendir de días anteriores para el cobrador logueado.
   * Alimenta el modal in-app que aparece cuando el cobrador abre la app
   * al día siguiente sin haber rendido. Devuelve `[]` (nunca lanza) si el
   * usuario no está vinculado como cobrador, para que el dashboard
   * pueda invocarlo sin preocuparse por usuarios no-cobradores.
   */
  async pendientesDiasAnteriores(empresaId: string, usuarioId: string) {
    const cobrador = await this.vendedores.findCobradorVinculado(empresaId, usuarioId);
    if (!cobrador) return [];
    return this.rendiciones.getPendientesDiasAnterioresPorCobrador(empresaId, cobrador.id);
  }
}
