import { Injectable, NotFoundException, Logger } from '@nestjs/common';
import { AuditService } from '../audit/audit.service';
import { PrismaService } from '../prisma/prisma.service';
import { CreateAsignacionDto } from './dto/create-asignacion.dto';
import { UpdateAsignacionDto } from './dto/update-asignacion.dto';

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

  async create(dto: CreateAsignacionDto, empresa_id?: string, actor_id?: string) {
    const asignacion = await this.prisma.asignacion_sucursal_caja_usuario.create({
      data: {
        sucursal_id: dto.sucursal_id,
        usuario_id: dto.usuario_id,
        caja_id: dto.caja_id,
      },
      include: {
        sucursal: true,
        usuario: true,
        caja: true,
      },
    });
    this.logger.log(
      `Asignación creada: ${asignacion.id} | Usuario: ${dto.usuario_id} | Sucursal: ${dto.sucursal_id}`,
      'AsignacionesSucursalService',
    );
    await this.auditService.log({
      empresa_id,
      user_id: actor_id,
      action: 'CREATE',
      entity_type: 'asignacion_sucursal',
      entity_id: asignacion.id,
      descripcion: `Asignación creada: usuario ${dto.usuario_id} → sucursal ${dto.sucursal_id}${dto.caja_id ? ` / caja ${dto.caja_id}` : ''}`,
      new_value: { sucursal_id: dto.sucursal_id, usuario_id: dto.usuario_id, caja_id: dto.caja_id },
    });
    return { message: 'Asignación creada exitosamente', data: asignacion };
  }

  async findAll(empresa_id?: string) {
    const asignaciones = await this.prisma.asignacion_sucursal_caja_usuario.findMany({
      where: empresa_id
        ? {
            sucursal: {
              empresa_id,
            },
          }
        : undefined,
      include: {
        sucursal: true,
        usuario: true,
        caja: true,
      },
      orderBy: { created_at: 'desc' },
    });
    return asignaciones;
  }

  async findByUsuario(usuario_id: string) {
    const asignaciones = await this.prisma.asignacion_sucursal_caja_usuario.findMany({
      where: { usuario_id },
      include: {
        sucursal: {
          include: {
            cajas: true, // Incluir todas las cajas de la sucursal
          },
        },
        caja: true,
      },
    });

    // Expandir asignaciones: si caja_id es null (acceso_todas), crear una entrada por cada caja de la sucursal
    const resultado = [];
    for (const asig of asignaciones) {
      const sucursalData = asig.sucursal ? { ...asig.sucursal, cajas: undefined } : null;
      if (!asig.caja_id && asig.sucursal?.cajas?.length) {
        // Expandir todas las cajas de la sucursal
        for (const caja of asig.sucursal.cajas) {
          resultado.push({
            id: asig.id,
            sucursal_id: asig.sucursal_id,
            caja_id: caja.id,
            usuario_id: asig.usuario_id,
            sucursal: sucursalData,
            caja,
            acceso_todas: true,
          });
        }
      } else {
        resultado.push({
          id: asig.id,
          sucursal_id: asig.sucursal_id,
          caja_id: asig.caja_id,
          usuario_id: asig.usuario_id,
          sucursal: sucursalData,
          caja: asig.caja,
          acceso_todas: !asig.caja_id,
        });
      }
    }
    return resultado;
  }

  async findOne(id: string) {
    const asignacion = await this.prisma.asignacion_sucursal_caja_usuario.findUnique({
      where: { id },
      include: {
        sucursal: true,
        usuario: true,
        caja: true,
      },
    });
    if (!asignacion) throw new NotFoundException('Asignación no encontrada');
    return asignacion;
  }

  async update(id: string, dto: UpdateAsignacionDto, empresa_id?: string, actor_id?: string) {
    const existing = await this.prisma.asignacion_sucursal_caja_usuario.findUnique({
      where: { id },
    });
    if (!existing) throw new NotFoundException('Asignación no encontrada');

    const asignacion = await this.prisma.asignacion_sucursal_caja_usuario.update({
      where: { id },
      data: {
        sucursal_id: dto.sucursal_id,
        usuario_id: dto.usuario_id,
        caja_id: dto.caja_id,
      },
      include: {
        sucursal: true,
        usuario: true,
        caja: true,
      },
    });
    this.logger.log(`Asignación actualizada: ${id}`, 'AsignacionesSucursalService');
    await this.auditService.log({
      empresa_id,
      user_id: actor_id,
      action: 'UPDATE',
      entity_type: 'asignacion_sucursal',
      entity_id: id,
      descripcion: `Asignación actualizada: ${id}`,
      old_value: { sucursal_id: existing.sucursal_id, usuario_id: existing.usuario_id, caja_id: existing.caja_id },
      new_value: { sucursal_id: dto.sucursal_id, usuario_id: dto.usuario_id, caja_id: dto.caja_id },
    });
    return { message: 'Asignación actualizada exitosamente', data: asignacion };
  }

  async remove(id: string, empresa_id?: string, actor_id?: string) {
    const existing = await this.prisma.asignacion_sucursal_caja_usuario.findUnique({
      where: { id },
    });
    if (!existing) throw new NotFoundException('Asignación no encontrada');

    await this.prisma.asignacion_sucursal_caja_usuario.delete({ where: { id } });
    this.logger.log(`Asignación eliminada: ${id}`, 'AsignacionesSucursalService');
    await this.auditService.log({
      empresa_id,
      user_id: actor_id,
      action: 'DELETE',
      entity_type: 'asignacion_sucursal',
      entity_id: id,
      descripcion: `Asignación eliminada: usuario ${existing.usuario_id} → sucursal ${existing.sucursal_id}`,
      old_value: { sucursal_id: existing.sucursal_id, usuario_id: existing.usuario_id, caja_id: existing.caja_id },
    });
    return { message: 'Asignación eliminada exitosamente' };
  }
}
