import { BadRequestException, Injectable, NotFoundException, Logger } from '@nestjs/common';
import { AuditService } from 'src/audit/audit.service';
import { PrismaService } from '../prisma/prisma.service';
import { CreateAtributoDto } from './dto/create-atributo.dto';
import { UpdateAtributoDto } from './dto/update-atributo.dto';
import { CreateAtributoValorDto } from './dto/create-atributo-valor.dto';
import { UpdateAtributoValorDto } from './dto/update-atributo-valor.dto';

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

  // ─── ATRIBUTOS ──────────────────────────────────────────────

  async createAtributo(dto: CreateAtributoDto, empresa_id: string, user_id?: string) {
    const atributo = await this.prisma.producto_atributos.create({
      data: {
        empresa_id,
        nombre: dto.nombre,
        descripcion: dto.descripcion,
        orden: dto.orden ?? 0,
      },
    });
    this.logger.log(`Atributo creado: ${atributo.nombre} (${atributo.id})`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'CREATE',
      entity_type: 'producto_atributo',
      entity_id: atributo.id,
      descripcion: `Atributo creado: ${atributo.nombre}`,
      new_value: { nombre: atributo.nombre, descripcion: atributo.descripcion },
    });
    return { message: 'Atributo creado exitosamente', data: atributo };
  }

  async findAllAtributos(empresa_id: string) {
    return this.prisma.producto_atributos.findMany({
      where: { empresa_id, active: true },
      include: {
        producto_atributo_valores: {
          where: { active: true },
          orderBy: { orden: 'asc' },
        },
      },
      orderBy: { orden: 'asc' },
    });
  }

  async findOneAtributo(id: string) {
    const atributo = await this.prisma.producto_atributos.findUnique({
      where: { id },
      include: {
        producto_atributo_valores: {
          where: { active: true },
          orderBy: { orden: 'asc' },
        },
      },
    });
    if (!atributo) throw new NotFoundException('Atributo no encontrado');
    return atributo;
  }

  async updateAtributo(id: string, dto: UpdateAtributoDto, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.producto_atributos.findUnique({ where: { id } });
    if (!existing) throw new NotFoundException('Atributo no encontrado');

    const atributo = await this.prisma.producto_atributos.update({
      where: { id },
      data: {
        nombre: dto.nombre,
        descripcion: dto.descripcion,
        orden: dto.orden,
        updated_at: new Date(),
      },
    });
    this.logger.log(`Atributo actualizado: ${atributo.nombre} (${id})`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id: empresa_id ?? existing.empresa_id,
      user_id,
      action: 'UPDATE',
      entity_type: 'producto_atributo',
      entity_id: id,
      descripcion: `Atributo actualizado: ${atributo.nombre}`,
      old_value: { nombre: existing.nombre, descripcion: existing.descripcion },
      new_value: { nombre: atributo.nombre, descripcion: atributo.descripcion },
    });
    return { message: 'Atributo actualizado exitosamente', data: atributo };
  }

  async toggleAtributo(id: string, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.producto_atributos.findUnique({ where: { id } });
    if (!existing) throw new NotFoundException('Atributo no encontrado');

    const atributo = await this.prisma.producto_atributos.update({
      where: { id },
      data: { active: !existing.active, updated_at: new Date() },
    });
    const action = atributo.active ? 'ACTIVATE' : 'DEACTIVATE';
    this.logger.log(`Atributo (${id}) ${atributo.active ? 'activado' : 'desactivado'}`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id: empresa_id ?? existing.empresa_id,
      user_id,
      action,
      entity_type: 'producto_atributo',
      entity_id: id,
      descripcion: `Atributo ${atributo.active ? 'activado' : 'desactivado'}: ${existing.nombre}`,
      old_value: { active: existing.active },
      new_value: { active: atributo.active },
    });
    return { message: 'Estado del atributo actualizado', data: atributo };
  }

  async removeAtributo(id: string, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.producto_atributos.findUnique({ where: { id } });
    if (!existing) throw new NotFoundException('Atributo no encontrado');

    // Verificar si tiene valores con variantes asociadas
    const variantesCount = await this.prisma.producto_variante_valores.count({
      where: { atributo_valor: { atributo_id: id } },
    });
    if (variantesCount > 0) {
      throw new BadRequestException(
        `No se puede eliminar el atributo porque tiene ${variantesCount} variante(s) asociada(s)`,
      );
    }

    await this.prisma.producto_atributos.delete({ where: { id } });
    this.logger.log(`Atributo eliminado: ${existing.nombre} (${id})`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id: empresa_id ?? existing.empresa_id,
      user_id,
      action: 'DELETE',
      entity_type: 'producto_atributo',
      entity_id: id,
      descripcion: `Atributo eliminado: ${existing.nombre}`,
      old_value: { nombre: existing.nombre },
    });
    return { message: 'Atributo eliminado exitosamente' };
  }

  // ─── VALORES DE ATRIBUTO ───────────────────────────────────

  async createValor(dto: CreateAtributoValorDto, empresa_id: string, user_id?: string) {
    // Verificar que el atributo pertenece a la empresa
    const atributo = await this.prisma.producto_atributos.findUnique({
      where: { id: dto.atributo_id },
    });
    if (!atributo) throw new NotFoundException('Atributo no encontrado');
    if (atributo.empresa_id !== empresa_id) {
      throw new BadRequestException('El atributo no pertenece a su empresa');
    }

    const valor = await this.prisma.producto_atributo_valores.create({
      data: {
        atributo_id: dto.atributo_id,
        valor: dto.valor,
        codigo: dto.codigo,
        color_hex: dto.color_hex,
        orden: dto.orden ?? 0,
      },
    });
    this.logger.log(`Valor de atributo creado: ${valor.valor} (${valor.id})`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'CREATE',
      entity_type: 'producto_atributo_valor',
      entity_id: valor.id,
      descripcion: `Valor creado: ${valor.valor} para atributo ${atributo.nombre}`,
      new_value: { valor: valor.valor, codigo: valor.codigo, atributo: atributo.nombre },
    });
    return { message: 'Valor creado exitosamente', data: valor };
  }

  async findValoresByAtributo(atributo_id: string) {
    return this.prisma.producto_atributo_valores.findMany({
      where: { atributo_id, active: true },
      orderBy: { orden: 'asc' },
    });
  }

  async updateValor(id: string, dto: UpdateAtributoValorDto, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.producto_atributo_valores.findUnique({
      where: { id },
      include: { atributo: true },
    });
    if (!existing) throw new NotFoundException('Valor de atributo no encontrado');

    const valor = await this.prisma.producto_atributo_valores.update({
      where: { id },
      data: {
        valor: dto.valor,
        codigo: dto.codigo,
        color_hex: dto.color_hex,
        orden: dto.orden,
        updated_at: new Date(),
      },
    });
    this.logger.log(`Valor de atributo actualizado: ${valor.valor} (${id})`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id: empresa_id ?? existing.atributo.empresa_id,
      user_id,
      action: 'UPDATE',
      entity_type: 'producto_atributo_valor',
      entity_id: id,
      descripcion: `Valor actualizado: ${valor.valor}`,
      old_value: { valor: existing.valor, codigo: existing.codigo },
      new_value: { valor: valor.valor, codigo: valor.codigo },
    });
    return { message: 'Valor actualizado exitosamente', data: valor };
  }

  async toggleValor(id: string, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.producto_atributo_valores.findUnique({
      where: { id },
      include: { atributo: true },
    });
    if (!existing) throw new NotFoundException('Valor de atributo no encontrado');

    const valor = await this.prisma.producto_atributo_valores.update({
      where: { id },
      data: { active: !existing.active, updated_at: new Date() },
    });
    const action = valor.active ? 'ACTIVATE' : 'DEACTIVATE';
    this.logger.log(`Valor (${id}) ${valor.active ? 'activado' : 'desactivado'}`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id: empresa_id ?? existing.atributo.empresa_id,
      user_id,
      action,
      entity_type: 'producto_atributo_valor',
      entity_id: id,
      descripcion: `Valor ${valor.active ? 'activado' : 'desactivado'}: ${existing.valor}`,
      old_value: { active: existing.active },
      new_value: { active: valor.active },
    });
    return { message: 'Estado del valor actualizado', data: valor };
  }

  async removeValor(id: string, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.producto_atributo_valores.findUnique({
      where: { id },
      include: { atributo: true },
    });
    if (!existing) throw new NotFoundException('Valor de atributo no encontrado');

    // Verificar si tiene variantes asociadas
    const variantesCount = await this.prisma.producto_variante_valores.count({
      where: { atributo_valor_id: id },
    });
    if (variantesCount > 0) {
      throw new BadRequestException(
        `No se puede eliminar el valor porque tiene ${variantesCount} variante(s) asociada(s)`,
      );
    }

    await this.prisma.producto_atributo_valores.delete({ where: { id } });
    this.logger.log(`Valor eliminado: ${existing.valor} (${id})`, 'ProductoAtributosService');
    await this.auditService.log({
      empresa_id: empresa_id ?? existing.atributo.empresa_id,
      user_id,
      action: 'DELETE',
      entity_type: 'producto_atributo_valor',
      entity_id: id,
      descripcion: `Valor eliminado: ${existing.valor} del atributo ${existing.atributo.nombre}`,
      old_value: { valor: existing.valor, codigo: existing.codigo },
    });
    return { message: 'Valor eliminado exitosamente' };
  }
}
