import { Injectable, NotFoundException, Logger } from '@nestjs/common';
import { AuditService } from 'src/audit/audit.service';
import { PrismaService } from '../prisma/prisma.service';
import { CreateDepositoDto } from './dto/create-deposito.dto';
import { UpdateDepositoDto } from './dto/update-deposito.dto';
import { alcanceSucursalUsuario, filtroSucursalOperativo } from 'src/utils/alcance-sucursal';

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

  async create(dto: CreateDepositoDto, empresa_id: string, user_id?: string) {
    const deposito = await this.prisma.depositos.create({
      data: {
        sucursal_id: dto.sucursal_id,
        empresa_id,
        codigo: dto.codigo,
        descripcion: dto.descripcion,
        tipo: dto.tipo || 'fisico',
        es_principal: dto.es_principal || false,
      },
      include: { sucursal: true },
    });
    this.logger.log(`Depósito creado: ${deposito.descripcion} (${deposito.id})`, 'DepositosService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'CREATE',
      entity_type: 'deposito',
      entity_id: deposito.id,
      descripcion: `Depósito creado: ${deposito.descripcion} | Tipo: ${deposito.tipo}`,
      new_value: {
        descripcion: deposito.descripcion,
        codigo: deposito.codigo,
        tipo: deposito.tipo,
        sucursal_id: deposito.sucursal_id,
      },
    });
    return { message: 'Depósito creado exitosamente', data: deposito };
  }

  async findAll(empresa_id: string, sucursal_id?: string, usuario_id?: string) {
    // Mismo alcance por sucursal (y rubro del selector) que el stock: el usuario
    // sólo elige depósitos de sucursales que puede ver; una sucursal pedida fuera
    // del alcance devuelve vacío en vez de 403.
    const alcance = await alcanceSucursalUsuario(this.prisma, usuario_id, empresa_id);
    const filtroSucursal = filtroSucursalOperativo(alcance, sucursal_id);
    const depositos = await this.prisma.depositos.findMany({
      where: {
        empresa_id,
        active: true,
        ...(filtroSucursal !== undefined ? { sucursal_id: filtroSucursal } : {}),
      },
      include: { sucursal: true },
      orderBy: { created_at: 'desc' },
    });
    return depositos;
  }

  async findPrincipal(empresa_id: string, sucursal_id: string) {
    const deposito = await this.prisma.depositos.findFirst({
      where: {
        empresa_id,
        sucursal_id,
        es_principal: true,
        active: true,
      },
      include: { sucursal: true },
    });
    return deposito;
  }

  async validarDepositoPrincipal(empresa_id: string, sucursal_id: string) {
    const deposito = await this.findPrincipal(empresa_id, sucursal_id);
    return {
      existe: !!deposito,
      deposito: deposito,
      mensaje: deposito
        ? 'Depósito principal configurado correctamente'
        : 'No hay depósito principal configurado para esta sucursal. Configure uno antes de continuar.',
    };
  }

  async findOne(id: string) {
    const deposito = await this.prisma.depositos.findUnique({
      where: { id },
      include: { sucursal: true, stock_deposito: { include: { producto: true } } },
    });
    if (!deposito) throw new NotFoundException('Depósito no encontrado');
    return deposito;
  }

  async update(id: string, dto: UpdateDepositoDto, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.depositos.findUnique({ where: { id } });
    if (!existing) throw new NotFoundException('Depósito no encontrado');

    const deposito = await this.prisma.depositos.update({
      where: { id },
      data: {
        sucursal_id: dto.sucursal_id,
        codigo: dto.codigo,
        descripcion: dto.descripcion,
        tipo: dto.tipo,
        es_principal: dto.es_principal,
        updated_at: new Date(),
      },
      include: { sucursal: true },
    });
    this.logger.log(`Depósito actualizado: ${deposito.descripcion} (${id})`, 'DepositosService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'UPDATE',
      entity_type: 'deposito',
      entity_id: id,
      descripcion: `Depósito actualizado: ${deposito.descripcion}`,
      old_value: {
        descripcion: existing.descripcion,
        codigo: existing.codigo,
        tipo: existing.tipo,
        es_principal: existing.es_principal,
      },
      new_value: {
        descripcion: deposito.descripcion,
        codigo: deposito.codigo,
        tipo: deposito.tipo,
        es_principal: deposito.es_principal,
      },
    });
    return { message: 'Depósito actualizado exitosamente', data: deposito };
  }

  async toggleActive(id: string, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.depositos.findUnique({ where: { id } });
    if (!existing) throw new NotFoundException('Depósito no encontrado');

    const deposito = await this.prisma.depositos.update({
      where: { id },
      data: { active: !existing.active, updated_at: new Date() },
    });
    const action = deposito.active ? 'ACTIVATE' : 'DEACTIVATE';
    this.logger.log(`Depósito (${id}) ${deposito.active ? 'activado' : 'desactivado'}`, 'DepositosService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action,
      entity_type: 'deposito',
      entity_id: id,
      descripcion: `Depósito ${deposito.active ? 'activado' : 'desactivado'}: ${existing.descripcion}`,
      old_value: { active: existing.active },
      new_value: { active: deposito.active },
    });
    return { message: 'Estado del depósito actualizado', data: deposito };
  }

  async remove(id: string, empresa_id?: string, user_id?: string) {
    const existing = await this.prisma.depositos.findUnique({ where: { id } });
    if (!existing) throw new NotFoundException('Depósito no encontrado');

    await this.prisma.depositos.delete({ where: { id } });
    this.logger.log(`Depósito eliminado: ${existing.descripcion} (${id})`, 'DepositosService');
    await this.auditService.log({
      empresa_id,
      user_id,
      action: 'DELETE',
      entity_type: 'deposito',
      entity_id: id,
      descripcion: `Depósito eliminado: ${existing.descripcion}`,
      old_value: {
        descripcion: existing.descripcion,
        codigo: existing.codigo,
        tipo: existing.tipo,
        sucursal_id: existing.sucursal_id,
      },
    });
    return { message: 'Depósito eliminado exitosamente' };
  }
}
