import { BadRequestException, Injectable, NotFoundException, Logger } from '@nestjs/common';
import { AuditService } from 'src/audit/audit.service';
import { PrismaService } from '../prisma/prisma.service';
import { CreatePresentacionDto } from './dto/create-presentacion.dto';
import { UpdatePresentacionDto } from './dto/update-presentacion.dto';

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

  private async assertProductoEmpresa(producto_id: string, empresa_id: string) {
    const producto = await this.prisma.productos.findUnique({
      where: { id: producto_id },
      select: { id: true, empresa_id: true, descripcion: true },
    });
    if (!producto) throw new NotFoundException('Producto no encontrado');
    if (producto.empresa_id !== empresa_id) {
      throw new BadRequestException('El producto no pertenece a su empresa');
    }
    return producto;
  }

  async create(dto: CreatePresentacionDto, empresa_id: string, user_id?: string) {
    const producto = await this.assertProductoEmpresa(dto.producto_id, empresa_id);

    // Si es default, desactivar otros defaults del mismo producto
    if (dto.es_default) {
      await this.prisma.producto_presentaciones.updateMany({
        where: { producto_id: dto.producto_id, es_default: true },
        data: { es_default: false },
      });
    }

    const presentacion = await this.prisma.producto_presentaciones.create({
      data: {
        producto_id: dto.producto_id,
        nombre: dto.nombre,
        abreviatura: dto.abreviatura,
        factor_conversion: dto.factor_conversion,
        codigo_barra: dto.codigo_barra,
        precio: dto.precio,
        es_default: dto.es_default ?? false,
        orden: dto.orden ?? 0,
      },
    });
    this.logger.log(
      `Presentación creada: ${presentacion.nombre} para producto ${producto.descripcion} (${presentacion.id})`,
      'ProductoPresentacionesService',
    );
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'CREATE',
      entity_type: 'producto_presentacion',
      entity_id: presentacion.id,
      descripcion: `Presentación creada: ${presentacion.nombre} (factor: ${presentacion.factor_conversion}) para ${producto.descripcion}`,
      new_value: { nombre: presentacion.nombre, factor_conversion: Number(presentacion.factor_conversion), producto: producto.descripcion },
    });
    return { message: 'Presentación creada exitosamente', data: presentacion };
  }

  async findByProducto(producto_id: string) {
    return this.prisma.producto_presentaciones.findMany({
      where: { producto_id, active: true },
      orderBy: { orden: 'asc' },
    });
  }

  async findOne(id: string) {
    const presentacion = await this.prisma.producto_presentaciones.findUnique({
      where: { id },
    });
    if (!presentacion) throw new NotFoundException('Presentación no encontrada');
    return presentacion;
  }

  async update(id: string, dto: UpdatePresentacionDto, empresa_id: string, user_id?: string) {
    const existing = await this.prisma.producto_presentaciones.findUnique({
      where: { id },
      include: { producto: { select: { empresa_id: true, descripcion: true } } },
    });
    if (!existing) throw new NotFoundException('Presentación no encontrada');
    if (existing.producto.empresa_id !== empresa_id) {
      throw new BadRequestException('La presentación no pertenece a su empresa');
    }

    // Si se activa default, desactivar otros defaults
    if (dto.es_default) {
      await this.prisma.producto_presentaciones.updateMany({
        where: { producto_id: existing.producto_id, es_default: true, id: { not: id } },
        data: { es_default: false },
      });
    }

    const presentacion = await this.prisma.producto_presentaciones.update({
      where: { id },
      data: {
        nombre: dto.nombre,
        abreviatura: dto.abreviatura,
        factor_conversion: dto.factor_conversion,
        codigo_barra: dto.codigo_barra,
        precio: dto.precio,
        es_default: dto.es_default,
        orden: dto.orden,
        updated_at: new Date(),
      },
    });
    this.logger.log(`Presentación actualizada: ${presentacion.nombre} (${id})`, 'ProductoPresentacionesService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'UPDATE',
      entity_type: 'producto_presentacion',
      entity_id: id,
      descripcion: `Presentación actualizada: ${presentacion.nombre}`,
      old_value: { nombre: existing.nombre, factor_conversion: Number(existing.factor_conversion) },
      new_value: { nombre: presentacion.nombre, factor_conversion: Number(presentacion.factor_conversion) },
    });
    return { message: 'Presentación actualizada exitosamente', data: presentacion };
  }

  async toggleActive(id: string, empresa_id: string, user_id?: string) {
    const existing = await this.prisma.producto_presentaciones.findUnique({
      where: { id },
      include: { producto: { select: { empresa_id: true } } },
    });
    if (!existing) throw new NotFoundException('Presentación no encontrada');
    if (existing.producto.empresa_id !== empresa_id) {
      throw new BadRequestException('La presentación no pertenece a su empresa');
    }

    const presentacion = await this.prisma.producto_presentaciones.update({
      where: { id },
      data: { active: !existing.active, updated_at: new Date() },
    });
    const action = presentacion.active ? 'ACTIVATE' : 'DEACTIVATE';
    this.logger.log(`Presentación (${id}) ${presentacion.active ? 'activada' : 'desactivada'}`, 'ProductoPresentacionesService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action,
      entity_type: 'producto_presentacion',
      entity_id: id,
      descripcion: `Presentación ${presentacion.active ? 'activada' : 'desactivada'}: ${existing.nombre}`,
      old_value: { active: existing.active },
      new_value: { active: presentacion.active },
    });
    return { message: 'Estado de la presentación actualizado', data: presentacion };
  }

  async remove(id: string, empresa_id: string, user_id?: string) {
    const existing = await this.prisma.producto_presentaciones.findUnique({
      where: { id },
      include: { producto: { select: { empresa_id: true, descripcion: true } } },
    });
    if (!existing) throw new NotFoundException('Presentación no encontrada');
    if (existing.producto.empresa_id !== empresa_id) {
      throw new BadRequestException('La presentación no pertenece a su empresa');
    }

    await this.prisma.producto_presentaciones.delete({ where: { id } });
    this.logger.log(`Presentación eliminada: ${existing.nombre} (${id})`, 'ProductoPresentacionesService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'DELETE',
      entity_type: 'producto_presentacion',
      entity_id: id,
      descripcion: `Presentación eliminada: ${existing.nombre} del producto ${existing.producto.descripcion}`,
      old_value: { nombre: existing.nombre, factor_conversion: Number(existing.factor_conversion) },
    });
    return { message: 'Presentación eliminada exitosamente' };
  }
}
