import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateTasaIscDto, UpdateTasaIscDto } from '../dto/importaciones.dto';

type Tx = Prisma.TransactionClient;

@Injectable()
export class ImportacionesIscService {
  constructor(private readonly prisma: PrismaService) {}

  async findAll(empresaId: string) {
    return this.prisma.imp_isc_vehiculos.findMany({
      where: { OR: [{ empresa_id: empresaId }, { empresa_id: null }] },
      orderBy: [
        { vigente_desde: 'desc' },
        { anio_desde: 'asc' },
        { cc_desde: 'asc' },
      ],
    });
  }

  async create(empresaId: string, dto: CreateTasaIscDto) {
    this.validateRanges(dto);
    return this.prisma.imp_isc_vehiculos.create({
      data: {
        empresa_id: empresaId,
        anio_desde: dto.anio_desde,
        anio_hasta: dto.anio_hasta,
        cc_desde: dto.cc_desde,
        cc_hasta: dto.cc_hasta,
        tasa_isc_pct: dto.tasa_isc_pct,
        descripcion: dto.descripcion?.trim() || null,
        vigente_desde: new Date(dto.vigente_desde),
        vigente_hasta: dto.vigente_hasta ? new Date(dto.vigente_hasta) : null,
        activo: dto.activo ?? true,
      },
    });
  }

  async update(empresaId: string, id: string, dto: UpdateTasaIscDto) {
    const existing = await this.prisma.imp_isc_vehiculos.findFirst({
      where: { id, empresa_id: empresaId },
    });
    if (!existing) throw new NotFoundException('Tasa ISC no encontrada para esta empresa');
    const merged = { ...existing, ...dto } as any;
    this.validateRanges(merged);
    return this.prisma.imp_isc_vehiculos.update({
      where: { id },
      data: {
        ...(dto.anio_desde !== undefined && { anio_desde: dto.anio_desde }),
        ...(dto.anio_hasta !== undefined && { anio_hasta: dto.anio_hasta }),
        ...(dto.cc_desde !== undefined && { cc_desde: dto.cc_desde }),
        ...(dto.cc_hasta !== undefined && { cc_hasta: dto.cc_hasta }),
        ...(dto.tasa_isc_pct !== undefined && { tasa_isc_pct: dto.tasa_isc_pct }),
        ...(dto.descripcion !== undefined && { descripcion: dto.descripcion?.trim() || null }),
        ...(dto.vigente_desde !== undefined && { vigente_desde: new Date(dto.vigente_desde) }),
        ...(dto.vigente_hasta !== undefined && {
          vigente_hasta: dto.vigente_hasta ? new Date(dto.vigente_hasta) : null,
        }),
        ...(dto.activo !== undefined && { activo: dto.activo }),
        updated_at: new Date(),
      },
    });
  }

  async remove(empresaId: string, id: string) {
    const existing = await this.prisma.imp_isc_vehiculos.findFirst({
      where: { id, empresa_id: empresaId },
    });
    if (!existing) throw new NotFoundException('Tasa ISC no encontrada para esta empresa');
    await this.prisma.imp_isc_vehiculos.delete({ where: { id } });
    return { message: 'Tasa ISC eliminada' };
  }

  /**
   * Resuelve la tasa ISC vigente para un (anio, cilindradaCc, fechaReferencia) priorizando
   * las tasas específicas de la empresa sobre las del sistema (empresa_id IS NULL).
   */
  async lookupTasa(
    empresaId: string,
    anio: number,
    cilindradaCc: number,
    fechaReferencia: Date,
    tx?: Tx,
  ) {
    const db = tx ?? this.prisma;
    const candidatos = await db.imp_isc_vehiculos.findMany({
      where: {
        activo: true,
        OR: [{ empresa_id: empresaId }, { empresa_id: null }],
        anio_desde: { lte: anio },
        anio_hasta: { gte: anio },
        cc_desde: { lte: cilindradaCc },
        cc_hasta: { gte: cilindradaCc },
        vigente_desde: { lte: fechaReferencia },
        AND: [
          {
            OR: [
              { vigente_hasta: null },
              { vigente_hasta: { gte: fechaReferencia } },
            ],
          },
        ],
      },
      orderBy: [{ empresa_id: 'desc' }, { vigente_desde: 'desc' }],
    });
    return candidatos[0] ?? null;
  }

  private validateRanges(dto: { anio_desde: number; anio_hasta: number; cc_desde: number; cc_hasta: number }) {
    if (dto.anio_hasta < dto.anio_desde) {
      throw new BadRequestException('anio_hasta debe ser mayor o igual a anio_desde');
    }
    if (dto.cc_hasta < dto.cc_desde) {
      throw new BadRequestException('cc_hasta debe ser mayor o igual a cc_desde');
    }
  }
}
