import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateVehicleDto } from './dto/create-vehicle.dto';
import { UpdateVehicleDto } from './dto/update-vehicle.dto';
import { Vehicle, VehicleStatus } from './entities/vehicle.entity';

@Injectable()
export class VehiclesService {
  constructor(
    @InjectRepository(Vehicle)
    private readonly vehicleRepo: Repository<Vehicle>,
  ) {}

  async create(dto: CreateVehicleDto): Promise<Vehicle> {
    const existing = await this.vehicleRepo.findOne({
      where: { plateNumber: dto.plateNumber },
    });

    if (existing) {
      throw new ConflictException(
        `Vehicle with plate number ${dto.plateNumber} already exists`,
      );
    }

    const registrationNumber = `REG-${dto.vehicleType}-${Date.now()}`;
    const vehicle = this.vehicleRepo.create({
      ...dto,
      registrationNumber,
    });

    return this.vehicleRepo.save(vehicle);
  }

  async findAll(query: {
    search?: string;
    status?: VehicleStatus | string;
    page?: number;
    limit?: number;
    sortBy?: string;
    sortOrder?: 'ASC' | 'DESC';
  } = {}): Promise<Vehicle[]> {
    let qb = this.vehicleRepo.createQueryBuilder('v');

    if (query.search) {
      qb = qb.where(
        'v.plateNumber ILIKE :search OR v.manufacturer ILIKE :search',
        { search: `%${query.search}%` },
      );
    }

    if (query.status) {
      qb = qb.andWhere('v.status = :status', { status: query.status });
    }

    const sortBy = ['plateNumber', 'status', 'year', 'createdAt'].includes(
      query.sortBy ?? '',
    )
      ? query.sortBy
      : 'createdAt';
    const sortOrder = (query.sortOrder ?? 'DESC').toUpperCase();

    return qb
      .orderBy(`v.${sortBy}`, sortOrder as 'ASC' | 'DESC')
      .getMany();
  }

  async findById(id: string): Promise<Vehicle> {
    const vehicle = await this.vehicleRepo.findOne({ where: { id } });
    if (!vehicle) {
      throw new NotFoundException(`Vehicle ${id} not found`);
    }
    return vehicle;
  }

  async update(id: string, dto: UpdateVehicleDto): Promise<Vehicle> {
    const vehicle = await this.findById(id);

    if (dto.plateNumber && dto.plateNumber !== vehicle.plateNumber) {
      const existing = await this.vehicleRepo.findOne({
        where: { plateNumber: dto.plateNumber },
      });
      if (existing) {
        throw new ConflictException(
          `Vehicle with plate number ${dto.plateNumber} already exists`,
        );
      }
    }

    Object.assign(vehicle, dto);
    return this.vehicleRepo.save(vehicle);
  }

  async remove(id: string): Promise<void> {
    await this.findById(id);
    await this.vehicleRepo.softDelete(id);
  }
}
