import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateVehiculoDto } from './dto/create-vehiculo.dto';
import { UpdateVehiculoDto } from './dto/update-vehiculo.dto';

const include = {
  transportistas: {
    include: {
      personas: true,
    },
  },
  modalidad_transporte_r: true,
  tipo_transporte_r: true,
};

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

  /**
   * Valida que el número correspondiente al tipo de identificación esté cargado.
   * Convención: tipo_identificacion 1 = Matrícula (requiere nro_matricula),
   * 2 = Identificación (requiere nro_identificacion). Requerido por SIFEN para
   * la nota de remisión.
   */
  private validarIdentificacion(tipo: number | null | undefined, nroMatricula?: string | null, nroIdentificacion?: string | null): void {
    const matricula = nroMatricula?.trim() || '';
    const identificacion = nroIdentificacion?.trim() || '';
    if (tipo === 1 && !matricula) {
      throw new BadRequestException('El Nro. de matrícula es obligatorio cuando el tipo de identificación es "Matrícula".');
    }
    if (tipo === 2 && !identificacion) {
      throw new BadRequestException('El Nro. de identificación es obligatorio cuando el tipo de identificación es "Identificación".');
    }
    // Límites SIFEN: matrícula hasta 7, identificación hasta 20.
    if (matricula && matricula.length > 7) {
      throw new BadRequestException('El Nro. de matrícula no puede superar los 7 caracteres.');
    }
    if (identificacion && identificacion.length > 20) {
      throw new BadRequestException('El Nro. de identificación no puede superar los 20 caracteres.');
    }
  }

  async create(dto: CreateVehiculoDto, empresa_id: string) {
    this.validarIdentificacion(dto.tipo_identificacion, dto.nro_matricula, dto.nro_identificacion);
    return this.prisma.vehiculos.create({
      data: {
        empresa_id,
        transportista_id: dto.transportista_id,
        modalidad_transporte_id: dto.modalidad_transporte_id ?? null,
        tipo_transporte_id: dto.tipo_transporte_id ?? null,
        marca: dto.marca,
        modelo: dto.modelo,
        anio: dto.anio,
        tipo_vehiculo: dto.tipo_vehiculo ?? null,
        nro_matricula: dto.nro_matricula,
        nro_identificacion: dto.nro_identificacion,
        tipo_identificacion: dto.tipo_identificacion,
        capacidad_carga_kg: dto.capacidad_carga_kg,
        informacion_adicional: dto.informacion_adicional,
        activo: dto.activo ?? true,
      },
      include,
    });
  }

  async findAll(empresa_id: string, page = 1, limit = 20, activo?: boolean, transportista_id?: string) {
    const where: any = { empresa_id };
    if (activo !== undefined) where.activo = activo;
    if (transportista_id) where.transportista_id = transportista_id;
    const [items, total] = await Promise.all([
      this.prisma.vehiculos.findMany({
        where,
        include,
        skip: (page - 1) * limit,
        take: limit,
        orderBy: { created_at: 'desc' },
      }),
      this.prisma.vehiculos.count({ where }),
    ]);
    return { items, total, page, limit, lastPage: Math.ceil(total / limit) };
  }

  async search(empresa_id: string, q: string, limit = 20) {
    return this.prisma.vehiculos.findMany({
      where: {
        empresa_id,
        activo: true,
        OR: [
          { marca: { contains: q, mode: 'insensitive' } },
          { modelo: { contains: q, mode: 'insensitive' } },
          { nro_matricula: { contains: q, mode: 'insensitive' } },
        ],
      },
      include,
      take: limit,
    });
  }

  async findOne(id: string, empresa_id: string) {
    const item = await this.prisma.vehiculos.findFirst({ where: { id, empresa_id }, include });
    if (!item) throw new NotFoundException('Vehículo no encontrado');
    return item;
  }

  async findByTransportista(empresa_id: string, transportista_id: string) {
    return this.prisma.vehiculos.findMany({
      where: { empresa_id, transportista_id, activo: true },
      include,
    });
  }

  async update(id: string, empresa_id: string, dto: UpdateVehiculoDto) {
    const actual = await this.findOne(id, empresa_id);
    // DTO parcial: validar contra el estado resultante (dto ?? valor actual).
    this.validarIdentificacion(
      dto.tipo_identificacion ?? actual.tipo_identificacion,
      dto.nro_matricula ?? actual.nro_matricula,
      dto.nro_identificacion ?? actual.nro_identificacion,
    );
    return this.prisma.vehiculos.update({
      where: { id },
      data: {
        transportista_id: dto.transportista_id,
        modalidad_transporte_id: dto.modalidad_transporte_id,
        tipo_transporte_id: dto.tipo_transporte_id,
        marca: dto.marca,
        modelo: dto.modelo,
        anio: dto.anio,
        tipo_vehiculo: dto.tipo_vehiculo,
        nro_matricula: dto.nro_matricula,
        nro_identificacion: dto.nro_identificacion,
        tipo_identificacion: dto.tipo_identificacion,
        capacidad_carga_kg: dto.capacidad_carga_kg,
        informacion_adicional: dto.informacion_adicional,
        activo: dto.activo,
        updated_at: new Date(),
      },
      include,
    });
  }

  async remove(id: string, empresa_id: string) {
    await this.findOne(id, empresa_id);
    return this.prisma.vehiculos.update({
      where: { id },
      data: { activo: false, updated_at: new Date() },
    });
  }
}
