import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';

import { CreateWarehouseZoneDto } from './dto/create-warehouse-zone.dto';
import { UpdateWarehouseZoneDto } from './dto/update-warehouse-zone.dto';
import { WarehouseZone } from './entities/warehouse-zone.entity';
import { WarehouseYardsService } from './warehouse-yards.service';
import { WarehouseZonesRepository } from './warehouse-zones.repository';

@Injectable()
export class WarehouseZonesService {
  constructor(
    private readonly zonesRepository: WarehouseZonesRepository,
    private readonly yardsService: WarehouseYardsService,
  ) {}

  findByYard(yardId: string): Promise<WarehouseZone[]> {
    return this.zonesRepository.findAll({
      where: { yardId },
      order: { code: 'ASC' },
    });
  }

  async findById(id: string): Promise<WarehouseZone> {
    const zone = await this.zonesRepository.findById(id, {
      relations: { yard: { warehouse: true } },
    });

    if (!zone) {
      throw new NotFoundException(`Warehouse zone ${id} not found`);
    }

    return zone;
  }

  async create(yardId: string, dto: CreateWarehouseZoneDto): Promise<WarehouseZone> {
    // Ensure the parent yard exists.
    await this.yardsService.findById(yardId);
    await this.assertCodeUnique(yardId, dto.code.trim());

    return this.zonesRepository.create({
      yardId,
      name: dto.name.trim(),
      code: dto.code.trim(),
      type: dto.type,
      capacityWeight: dto.capacityWeight ?? null,
      capacityContainers: dto.capacityContainers ?? null,
      maxWeight: dto.maxWeight ?? dto.capacityWeight ?? null,
      maxVolume: dto.maxVolume ?? null,
      currentWeight: 0,
      currentContainers: 0,
      currentVolume: 0,
      status: 'ACTIVE',
      isActive: true,
    });
  }

  async update(id: string, dto: UpdateWarehouseZoneDto): Promise<WarehouseZone> {
    const existing = await this.findById(id);

    if (dto.code && dto.code.trim() !== existing.code) {
      await this.assertCodeUnique(existing.yardId, dto.code.trim(), id);
    }

    const status = dto.status ?? existing.status;

    const updated = await this.zonesRepository.update(id, {
      name: dto.name?.trim() ?? existing.name,
      code: dto.code?.trim() ?? existing.code,
      type: dto.type ?? existing.type,
      capacityWeight: dto.capacityWeight ?? existing.capacityWeight,
      capacityContainers: dto.capacityContainers ?? existing.capacityContainers,
      maxWeight: dto.maxWeight ?? existing.maxWeight,
      maxVolume: dto.maxVolume ?? existing.maxVolume,
      status,
      isActive: status === 'ACTIVE',
    });

    if (!updated) {
      throw new NotFoundException(`Warehouse zone ${id} not found`);
    }

    return this.findById(id);
  }

  private async assertCodeUnique(yardId: string, code: string, ignoreId?: string): Promise<void> {
    const [existing] = await this.zonesRepository.findAll({ where: { yardId, code } });

    if (existing && existing.id !== ignoreId) {
      throw new ConflictException(`Zone code ${code} already exists in this yard`);
    }
  }
}
