import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateContainerDto } from './dto/create-container.dto';
import { UpdateContainerDto } from './dto/update-container.dto';
import { AssignContainerToWagonDto } from './dto/assign-container-to-wagon.dto';
import { Container } from './entities/container.entity';
//import { ContainersRepository } from './containers.repository';
import { WagonsRepository } from '../wagons/wagons.repository';

@Injectable()
export class ContainersService {
  constructor(
    @InjectRepository(Container)
    private readonly containerRepo: Repository<Container>,
    private readonly wagonsRepository: WagonsRepository,
  ) {}

  async create(dto: CreateContainerDto): Promise<Container> {
    const container = this.containerRepo.create(dto);
    // Convert undefined to null for optional fields
    if (dto.wagonId === undefined) container.wagonId = null;
    if (dto.position === undefined) container.position = null;
    return this.containerRepo.save(container);
  }

  async findAll(): Promise<Container[]> {
    return this.containerRepo.find({ order: { containerNumber: 'ASC' } });
  }

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

  async update(id: string, dto: UpdateContainerDto): Promise<Container> {
    const container = await this.findById(id);
    Object.assign(container, dto);
    // Convert undefined to null for nullable fields
    if (dto.wagonId === undefined) container.wagonId = null;
    if (dto.position === undefined) container.position = null;
    return this.containerRepo.save(container);
  }

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

  async assignToWagon(containerId: string, dto: AssignContainerToWagonDto): Promise<Container> {
    const container = await this.findById(containerId);
    if (container.status === 'LOADED') {
      throw new ConflictException('Cannot reassign a loaded container');
    }

    const wagon = await this.wagonsRepository.findById(dto.wagonId);
    if (!wagon) throw new NotFoundException('Wagon not found');

    let position: number | null = dto.position ?? null; // convert undefined to null
    if (position === null) {
      const maxPos = await this.containerRepo
        .createQueryBuilder('c')
        .select('MAX(c.position)', 'max')
        .where('c.wagonId = :wagonId', { wagonId: wagon.id })
        .getRawOne();
      position = (maxPos?.max ?? 0) + 1;
    }

    container.wagonId = wagon.id;
    container.position = position; // now position is number | null, safe
    container.status = 'AVAILABLE';
    return this.containerRepo.save(container);
  }

  async unassignFromWagon(containerId: string): Promise<Container> {
    const container = await this.findById(containerId);
    if (container.status === 'LOADED') {
      throw new ConflictException('Cannot unassign a loaded container');
    }
    container.wagonId = null;
    container.position = null;
    container.status = 'AVAILABLE';
    return this.containerRepo.save(container);
  }
}