import {
  BadRequestException,
  ConflictException,
  ForbiddenException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../../prisma/prisma.service';
import {
  CreateTipoDocumentoDto,
  QueryTiposDocumentoDto,
  UpdateTipoDocumentoDto,
} from '../dto/legajos.dto';

/**
 * CRUD del catálogo de tipos de documento (M23).
 *
 * Reglas de negocio implementadas:
 * - `es_del_sistema = true` ⇒ inmutable (HTTP 403). Ni se renombra, ni se borra.
 *   SUPER_ADMIN puede desactivar (campo `activo = false`).
 * - Cada empresa ve sus tipos personalizados + todos los del sistema (empresa_id IS NULL).
 * - Código único por empresa (y único global entre los del sistema).
 * - `vencimiento_obligatorio = true` requiere `admite_vencimiento = true`.
 */
@Injectable()
export class LegajosTiposService {
  constructor(private readonly prisma: PrismaService) {}

  async listar(empresaId: string, query: QueryTiposDocumentoDto) {
    const where: Prisma.rrhh_legajo_tipos_documentoWhereInput = {
      OR: [
        { empresa_id: null }, // tipos del sistema
        { empresa_id: empresaId }, // tipos personalizados de esta empresa
      ],
    };

    if (!query.incluir_inactivos) {
      where.activo = true;
    }
    if (query.solo_personalizados) {
      where.OR = undefined;
      where.empresa_id = empresaId;
    }
    if (query.q) {
      const q = query.q.trim();
      where.AND = [
        {
          OR: [
            { codigo: { contains: q, mode: 'insensitive' } },
            { nombre: { contains: q, mode: 'insensitive' } },
          ],
        },
      ];
    }

    const data = await this.prisma.rrhh_legajo_tipos_documento.findMany({
      where,
      orderBy: [{ es_del_sistema: 'desc' }, { codigo: 'asc' }],
    });

    return { data, total: data.length };
  }

  async obtener(id: string, empresaId: string) {
    const tipo = await this.prisma.rrhh_legajo_tipos_documento.findFirst({
      where: {
        id,
        OR: [{ empresa_id: null }, { empresa_id: empresaId }],
      },
    });
    if (!tipo) throw new NotFoundException('Tipo de documento no encontrado');
    return tipo;
  }

  async crear(empresaId: string, dto: CreateTipoDocumentoDto, userId?: string) {
    this.validarReglas(dto);

    // El código no puede chocar con un tipo del sistema (empresa_id IS NULL)
    // ni con otro personalizado de la misma empresa.
    const conflicto = await this.prisma.rrhh_legajo_tipos_documento.findFirst({
      where: {
        codigo: dto.codigo.toUpperCase(),
        OR: [{ empresa_id: null }, { empresa_id: empresaId }],
      },
      select: { id: true, es_del_sistema: true },
    });
    if (conflicto) {
      throw new ConflictException(
        conflicto.es_del_sistema
          ? `El código "${dto.codigo}" está reservado por un tipo del sistema.`
          : `Ya existe un tipo personalizado con el código "${dto.codigo}".`,
      );
    }

    return this.prisma.rrhh_legajo_tipos_documento.create({
      data: {
        empresa_id: empresaId,
        codigo: dto.codigo.toUpperCase(),
        nombre: dto.nombre,
        descripcion: dto.descripcion ?? null,
        admite_vencimiento: dto.admite_vencimiento ?? false,
        vencimiento_obligatorio: dto.vencimiento_obligatorio ?? false,
        es_obligatorio: dto.es_obligatorio ?? false,
        dias_alerta_vencimiento: dto.dias_alerta_vencimiento ?? null,
        permite_multiples: dto.permite_multiples ?? false,
        es_del_sistema: false,
        activo: true,
        creado_por: userId ?? null,
      },
    });
  }

  async actualizar(id: string, empresaId: string, dto: UpdateTipoDocumentoDto) {
    const actual = await this.prisma.rrhh_legajo_tipos_documento.findFirst({
      where: { id },
    });
    if (!actual) throw new NotFoundException('Tipo de documento no encontrado');

    // Bloqueo para tipos del sistema.
    if (actual.es_del_sistema) {
      throw new ForbiddenException(
        'Los tipos del sistema no pueden editarse. Sólo SUPER_ADMIN puede desactivarlos.',
      );
    }

    // Pertenencia multi-empresa.
    if (actual.empresa_id !== empresaId) {
      throw new NotFoundException('Tipo de documento no encontrado');
    }

    // Reglas combinadas (vencimiento_obligatorio ⇒ admite_vencimiento).
    const admite = dto.admite_vencimiento ?? actual.admite_vencimiento;
    const obligatorio = dto.vencimiento_obligatorio ?? actual.vencimiento_obligatorio;
    if (obligatorio && !admite) {
      throw new BadRequestException(
        'No se puede marcar vencimiento_obligatorio sin admite_vencimiento = true.',
      );
    }

    return this.prisma.rrhh_legajo_tipos_documento.update({
      where: { id },
      data: {
        nombre: dto.nombre ?? undefined,
        descripcion: dto.descripcion !== undefined ? dto.descripcion : undefined,
        admite_vencimiento: dto.admite_vencimiento ?? undefined,
        vencimiento_obligatorio: dto.vencimiento_obligatorio ?? undefined,
        es_obligatorio: dto.es_obligatorio ?? undefined,
        dias_alerta_vencimiento:
          dto.dias_alerta_vencimiento !== undefined ? dto.dias_alerta_vencimiento : undefined,
        permite_multiples: dto.permite_multiples ?? undefined,
        activo: dto.activo ?? undefined,
      },
    });
  }

  async desactivar(id: string, empresaId: string) {
    const actual = await this.prisma.rrhh_legajo_tipos_documento.findFirst({ where: { id } });
    if (!actual) throw new NotFoundException('Tipo de documento no encontrado');

    if (actual.es_del_sistema) {
      throw new ForbiddenException('Los tipos del sistema no pueden eliminarse.');
    }
    if (actual.empresa_id !== empresaId) {
      throw new NotFoundException('Tipo de documento no encontrado');
    }

    return this.prisma.rrhh_legajo_tipos_documento.update({
      where: { id },
      data: { activo: false },
    });
  }

  private validarReglas(dto: CreateTipoDocumentoDto) {
    if (dto.vencimiento_obligatorio && !dto.admite_vencimiento) {
      throw new BadRequestException(
        'No se puede marcar vencimiento_obligatorio sin admite_vencimiento = true.',
      );
    }
  }
}
