import { BadRequestException, Injectable, NotFoundException, Logger } from '@nestjs/common';
import { AuditService } from 'src/audit/audit.service';
import { PrismaService } from '../prisma/prisma.service';
import { CreateVendedorCobradorDto, UpdateVendedorCobradorDto } from './dto';

@Injectable()
export class VendedoresCobradoresService {
  private readonly logger = new Logger(VendedoresCobradoresService.name);
  constructor(
    private prisma: PrismaService,
    private readonly auditService: AuditService,
  ) {}

  /**
   * Valida que no exista otro vendedor/cobrador activo en la misma empresa con el
   * mismo usuario_id. Permite 1:1 entre usuario y VC por empresa.
   */
  private async asegurarUsuarioUnico(
    empresaId: string,
    usuarioId: string | null | undefined,
    excluirId?: string,
  ) {
    if (!usuarioId) return;
    const existente = await this.prisma.vendedores_cobradores.findFirst({
      where: {
        empresa_id: empresaId,
        usuario_id: usuarioId,
        active: true,
        ...(excluirId ? { id: { not: excluirId } } : {}),
      },
      select: { id: true, nombre: true, apellido: true, codigo: true },
    });
    if (existente) {
      const nombre = `${existente.nombre ?? ''} ${existente.apellido ?? ''}`.trim();
      const label = nombre || existente.codigo || existente.id;
      throw new BadRequestException(
        `Este usuario ya está vinculado a otro vendedor/cobrador activo: "${label}". Liberalo de ahí antes de asignarlo acá.`,
      );
    }
  }

  async create(empresaId: string, dto: CreateVendedorCobradorDto, user_id?: string) {
    await this.asegurarUsuarioUnico(empresaId, dto.usuario_id);
    const result = await this.prisma.vendedores_cobradores.create({
      data: {
        empresa_id: empresaId,
        tipo: dto.tipo,
        nombre: dto.nombre,
        apellido: dto.apellido,
        codigo: dto.codigo,
        documento: dto.documento,
        telefono: dto.telefono,
        email: dto.email,
        direccion: dto.direccion,
        usuario_id: dto.usuario_id,
        zona_id: dto.zona_id,
        comision_porcentaje: dto.comision_porcentaje,
        comision_fija: dto.comision_fija,
        comision_venta: dto.comision_venta,
        comision_cobranza: dto.comision_cobranza,
        meta_mensual: dto.meta_mensual,
        active: dto.active ?? true,
        regimen_comision: dto.regimen_comision ?? null,
        empleado_id: dto.empleado_id ?? null,
      },
      include: {
        zonas_cobranza: true,
        usuario: {
          select: {
            id: true,
            nombres: true,
            apellidos: true,
            email: true,
          },
        },
      },
    });
    this.logger.log(
      `Vendedor/Cobrador creado: ${result.nombre} (${result.id}) | Empresa: ${empresaId}`,
      'VendedoresCobradoresService',
    );
    await this.auditService.log({
      empresa_id: empresaId,
      user_id,
      action: 'CREATE',
      entity_type: 'vendedor_cobrador',
      entity_id: result.id,
      descripcion: `Vendedor/Cobrador creado: ${result.nombre} ${result.apellido ?? ''} | Tipo: ${result.tipo} | Empresa: ${empresaId}`,
      new_value: { nombre: result.nombre, tipo: result.tipo, codigo: result.codigo },
    });
    return result;
  }

  async findAll(
    empresaId: string,
    filters?: {
      tipo?: string;
      active?: boolean;
      zona_id?: string;
      search?: string;
    },
  ) {
    console.log({});
    const where: any = { empresa_id: empresaId };

    if (filters?.tipo) {
      where.tipo = filters.tipo;
    }

    if (filters?.active !== undefined) {
      where.active = filters.active;
    }

    if (filters?.zona_id) {
      where.zona_id = filters.zona_id;
    }

    if (filters?.search) {
      where.OR = [
        { nombre: { contains: filters.search, mode: 'insensitive' } },
        { apellido: { contains: filters.search, mode: 'insensitive' } },
        { codigo: { contains: filters.search, mode: 'insensitive' } },
        { documento: { contains: filters.search, mode: 'insensitive' } },
        { email: { contains: filters.search, mode: 'insensitive' } },
      ];
    }

    return this.prisma.vendedores_cobradores.findMany({
      where,
      include: {
        zonas_cobranza: true,
        usuario: {
          select: {
            id: true,
            nombres: true,
            apellidos: true,
            email: true,
          },
        },
        _count: {
          select: {
            asignaciones_vendedor: true,
            asignaciones_cobrador: true,
            comisiones: true,
          },
        },
      },
      orderBy: { nombre: 'asc' },
    });
  }

  async findOne(empresaId: string, id: string) {
    const vendedorCobrador = await this.prisma.vendedores_cobradores.findFirst({
      where: { id, empresa_id: empresaId },
      include: {
        zonas_cobranza: true,
        usuario: {
          select: {
            id: true,
            nombres: true,
            apellidos: true,
            email: true,
          },
        },
        _count: {
          select: {
            asignaciones_vendedor: true,
            asignaciones_cobrador: true,
            comisiones: true,
          },
        },
      },
    });

    if (!vendedorCobrador) {
      throw new NotFoundException('Vendedor/Cobrador no encontrado');
    }

    return vendedorCobrador;
  }

  async update(empresaId: string, id: string, dto: UpdateVendedorCobradorDto, user_id?: string) {
    const old = await this.findOne(empresaId, id);
    if (dto.usuario_id !== undefined) {
      await this.asegurarUsuarioUnico(empresaId, dto.usuario_id, id);
    }

    const result = await this.prisma.vendedores_cobradores.update({
      where: { id },
      data: {
        tipo: dto.tipo,
        nombre: dto.nombre,
        apellido: dto.apellido,
        codigo: dto.codigo,
        documento: dto.documento,
        telefono: dto.telefono,
        email: dto.email,
        direccion: dto.direccion,
        usuario_id: dto.usuario_id,
        zona_id: dto.zona_id,
        comision_porcentaje: dto.comision_porcentaje,
        comision_fija: dto.comision_fija,
        comision_venta: dto.comision_venta,
        comision_cobranza: dto.comision_cobranza,
        meta_mensual: dto.meta_mensual,
        active: dto.active,
        regimen_comision: dto.regimen_comision,
        empleado_id: dto.empleado_id,
        updated_at: new Date(),
      },
      include: {
        zonas_cobranza: true,
        usuario: {
          select: {
            id: true,
            nombres: true,
            apellidos: true,
            email: true,
          },
        },
      },
    });
    this.logger.log(`Vendedor/Cobrador actualizado: ${result.nombre} (${id})`, 'VendedoresCobradoresService');
    await this.auditService.log({
      empresa_id: empresaId,
      user_id,
      action: 'UPDATE',
      entity_type: 'vendedor_cobrador',
      entity_id: id,
      descripcion: `Vendedor/Cobrador actualizado: ${result.nombre} ${result.apellido ?? ''}`,
      old_value: { nombre: old.nombre, tipo: old.tipo, active: old.active },
      new_value: { nombre: dto.nombre, tipo: dto.tipo, active: dto.active },
    });
    return result;
  }

  async remove(empresaId: string, id: string, user_id?: string) {
    const vendedorCobrador = await this.findOne(empresaId, id);

    // Verificar si tiene asignaciones activas
    const asignacionesActivas = await this.prisma.asignacion_facturas.count({
      where: {
        OR: [
          { vendedor_id: id, estado: { in: ['pendiente', 'en_ruta'] } },
          { cobrador_id: id, estado: { in: ['pendiente', 'en_ruta'] } },
        ],
      },
    });

    if (asignacionesActivas > 0) {
      throw new BadRequestException('No se puede eliminar: tiene asignaciones de facturas activas');
    }

    // Soft delete - solo desactivar
    const result = await this.prisma.vendedores_cobradores.update({
      where: { id },
      data: { active: false, updated_at: new Date() },
    });
    this.logger.log(
      `Vendedor/Cobrador desactivado (eliminado): ${result.nombre} (${id})`,
      'VendedoresCobradoresService',
    );
    await this.auditService.log({
      empresa_id: empresaId,
      user_id,
      action: 'DELETE',
      entity_type: 'vendedor_cobrador',
      entity_id: id,
      descripcion: `Vendedor/Cobrador eliminado (desactivado): ${vendedorCobrador.nombre} ${vendedorCobrador.apellido ?? ''}`,
      old_value: { active: vendedorCobrador.active, nombre: vendedorCobrador.nombre },
    });
    return result;
  }

  async toggleActive(empresaId: string, id: string, user_id?: string) {
    const vendedorCobrador = await this.findOne(empresaId, id);

    const result = await this.prisma.vendedores_cobradores.update({
      where: { id },
      data: {
        active: !vendedorCobrador.active,
        updated_at: new Date(),
      },
    });
    const action = result.active ? 'ACTIVATE' : 'DEACTIVATE';
    this.logger.log(
      `Vendedor/Cobrador (${id}) ${result.active ? 'activado' : 'desactivado'}`,
      'VendedoresCobradoresService',
    );
    await this.auditService.log({
      empresa_id: empresaId,
      user_id,
      action,
      entity_type: 'vendedor_cobrador',
      entity_id: id,
      descripcion: `Vendedor/Cobrador ${result.active ? 'activado' : 'desactivado'}: ${vendedorCobrador.nombre}`,
      old_value: { active: vendedorCobrador.active },
      new_value: { active: result.active },
    });
    return result;
  }

  // Obtener estadísticas del vendedor/cobrador
  async getEstadisticas(empresaId: string, id: string, periodo?: { desde: Date; hasta: Date }) {
    await this.findOne(empresaId, id);

    const whereComisiones: any = {
      vendedor_cobrador_id: id,
      empresa_id: empresaId,
    };

    if (periodo) {
      whereComisiones.created_at = {
        gte: periodo.desde,
        lte: periodo.hasta,
      };
    }

    const [comisiones, asignacionesVendedor, asignacionesCobrador] = await Promise.all([
      this.prisma.comisiones.aggregate({
        where: whereComisiones,
        _sum: { monto_comision: true, monto_base: true },
        _count: true,
      }),
      this.prisma.asignacion_facturas.count({
        where: { vendedor_id: id, empresa_id: empresaId },
      }),
      this.prisma.asignacion_facturas.count({
        where: { cobrador_id: id, empresa_id: empresaId },
      }),
    ]);

    return {
      total_comisiones: comisiones._sum.monto_comision || 0,
      total_ventas_cobranzas: comisiones._sum.monto_base || 0,
      cantidad_operaciones: comisiones._count,
      facturas_como_vendedor: asignacionesVendedor,
      facturas_como_cobrador: asignacionesCobrador,
    };
  }

  // Obtener vendedores disponibles para asignación
  async findVendedoresActivos(empresaId: string) {
    return this.prisma.vendedores_cobradores.findMany({
      where: {
        empresa_id: empresaId,
        active: true,
        tipo: { in: ['vendedor', 'ambos'] },
      },
      select: {
        id: true,
        nombre: true,
        apellido: true,
        codigo: true,
        usuario_id: true,
        comision_porcentaje: true,
        supervisores_asignados: {
          select: { supervisor: { select: { id: true, nombre: true, apellido: true } } },
          take: 1,
        },
      },
      orderBy: { nombre: 'asc' },
    });
  }

  // Obtener cobradores disponibles para asignación (filtro estricto por empresa)
  async findCobradoresActivos(empresaId: string) {
    return this.prisma.vendedores_cobradores.findMany({
      where: {
        empresa_id: empresaId,
        active: true,
        tipo: { in: ['cobrador', 'ambos'] },
      },
      select: {
        id: true,
        nombre: true,
        apellido: true,
        codigo: true,
        zona_id: true,
        empresa_id: true,
        zonas_cobranza: {
          select: { nombre: true },
        },
        supervisores_asignados: {
          select: { supervisor: { select: { id: true, nombre: true, apellido: true } } },
          take: 1,
        },
      },
      orderBy: { nombre: 'asc' },
    });
  }

  async findCobradorVinculado(empresaId: string, userId: string) {
    // orderBy explícito: si hay duplicados (data sucia), siempre devolver el mismo.
    return this.prisma.vendedores_cobradores.findFirst({
      where: {
        empresa_id: empresaId,
        usuario_id: userId,
        active: true,
        tipo: { in: ['cobrador', 'ambos'] },
      },
      orderBy: { id: 'asc' },
      select: { id: true, nombre: true, apellido: true, codigo: true, tipo: true },
    });
  }

  /**
   * Diagnóstico: devuelve por qué un usuario NO está siendo reconocido como
   * cobrador (para mensajes de error útiles en mobile). Verifica de menor a
   * mayor restricción.
   */
  async diagnosticarVinculoCobrador(empresaId: string, userId: string) {
    // 1) Alguna vinculación a este usuario en esta empresa
    const anyEmpresa = await this.prisma.vendedores_cobradores.findFirst({
      where: { empresa_id: empresaId, usuario_id: userId },
      select: { id: true, nombre: true, apellido: true, tipo: true, active: true },
    });
    if (!anyEmpresa) {
      // 2) Quizás está vinculado en OTRA empresa
      const enOtraEmpresa = await this.prisma.vendedores_cobradores.findFirst({
        where: { usuario_id: userId },
        select: { id: true, empresa_id: true },
      });
      // Sufijos cortos del UUID para que el cobrador pueda comparar con el del admin
      const short = (s?: string | null) => (s ? s.slice(-8) : '?');
      return {
        razon: enOtraEmpresa
          ? 'vinculado_otra_empresa'
          : 'sin_vinculacion',
        mensaje: enOtraEmpresa
          ? `Tu usuario está vinculado en otra empresa (…${short(enOtraEmpresa.empresa_id)}). Estás conectado en empresa …${short(empresaId)}. Cambiá de empresa o pedí vinculación en ésta.`
          : `Tu usuario (…${short(userId)}) no está vinculado a ningún vendedor/cobrador. Pedí al admin que te vincule en Contactos → Vendedores y Cobradores.`,
      };
    }
    if (!anyEmpresa.active) {
      return {
        razon: 'inactivo',
        mensaje: `El vendedor/cobrador "${anyEmpresa.nombre} ${anyEmpresa.apellido ?? ''}" está marcado como inactivo. Pedí que lo reactiven.`,
      };
    }
    if (anyEmpresa.tipo === 'vendedor') {
      return {
        razon: 'solo_vendedor',
        mensaje: `Tu usuario está vinculado pero solo como "Vendedor". Para rendir necesitás tipo "Cobrador" o "Ambos". Pedí que cambien el tipo.`,
      };
    }
    return { razon: 'ok', mensaje: null };
  }
}
