import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { FindOptionsOrder, FindOptionsWhere, ILike, Repository } from 'typeorm';
import { CreateTrainDto } from './dto/create-train.dto';
import { UpdateTrainDto } from './dto/update-train.dto';
import { Train } from './entities/train.entity';

@Injectable()
export class TrainsService {
  constructor(
    @InjectRepository(Train)
    private readonly trainRepo: Repository<Train>,
  ) {}

  create(dto: CreateTrainDto): Promise<Train> {
    const train = this.trainRepo.create(dto);
    return this.trainRepo.save(train);
  }

  findAll(query: Record<string, string | undefined> = {}): Promise<Train[]> {
    const where: FindOptionsWhere<Train>[] | FindOptionsWhere<Train> = [];
    const search = query.search?.trim();
    const status = query.status?.trim();

    if (search) {
      where.push({ code: ILike(`%${search}%`), ...(status ? { status: status as Train['status'] } : {}) });
      where.push({ trainNumber: ILike(`%${search}%`), ...(status ? { status: status as Train['status'] } : {}) });
      where.push({ trainName: ILike(`%${search}%`), ...(status ? { status: status as Train['status'] } : {}) });
    }

    const sortBy = ['code', 'trainNumber', 'trainName', 'capacityTons', 'status'].includes(query.sortBy ?? '')
      ? (query.sortBy as keyof Train)
      : 'code';
    const sortOrder = query.sortOrder?.toUpperCase() === 'DESC' ? 'DESC' : 'ASC';

    return this.trainRepo.find({
      where: search ? where : status ? { status: status as Train['status'] } : {},
      order: { [sortBy]: sortOrder } as FindOptionsOrder<Train>,
      skip: query.page && query.limit ? (Number(query.page) - 1) * Number(query.limit) : undefined,
      take: query.limit ? Number(query.limit) : undefined,
    });
  }

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

  async update(id: string, dto: UpdateTrainDto): Promise<Train> {
    const train = await this.findById(id);
    Object.assign(train, dto);
    // Convert undefined to null for optional fields if needed
    return this.trainRepo.save(train);
  }

  async remove(id: string): Promise<void> {
    const train = await this.findById(id);
    await this.trainRepo.remove(train);
  }
}
