import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, IsNull, FindOptionsWhere } from 'typeorm';
import { ClsService } from 'nestjs-cls';
import { TenantAwareRepository } from '../../../common/repositories/tenant-aware.repository';
import {
  SupplierCostPriceEntity,
  SupplierCostPriceMode,
} from '../../../entities/supplier-cost-price.entity';

@Injectable()
export class SupplierCostPriceRepository extends TenantAwareRepository<SupplierCostPriceEntity> {
  public readonly ormRepo: Repository<SupplierCostPriceEntity>;

  constructor(
    @InjectRepository(SupplierCostPriceEntity) repo: Repository<SupplierCostPriceEntity>,
    cls: ClsService,
  ) {
    super(repo, cls);
    this.ormRepo = repo;
  }

  /**
   * Primary read path — resolve the cost for a specific
   * (supplier × transport_service × vehicle_type × season?) tuple.
   * Seasons fall through: a null `season_id` in the DB row matches
   * every lookup season, while a seasoned row only matches its own
   * season. The seasoned row wins when both exist.
   */
  async findBestMatch(args: {
    supplier_id: string;
    transport_service_id: string;
    vehicle_type_id?: string | null;
    mode?: 'PVT' | 'SIC';
    season_id?: string | null;
  }): Promise<SupplierCostPriceEntity | null> {
    const tenantId = this.getTenantId();
    // SIC always carries vehicle_type_id IS NULL; the IsNull() guard
    // is required because plain `null` translates to `= NULL` (false).
    const mode: SupplierCostPriceMode =
      args.mode === 'SIC' ? SupplierCostPriceMode.SIC : SupplierCostPriceMode.PVT;
    const vehicleClause =
      mode === 'SIC' || args.vehicle_type_id == null ? IsNull() : args.vehicle_type_id;
    const baseWhere: FindOptionsWhere<SupplierCostPriceEntity> = {
      tenant_id: tenantId,
      is_deleted: false,
      supplier_id: args.supplier_id,
      transport_service_id: args.transport_service_id,
      vehicle_type_id: vehicleClause,
      mode,
    };
    // Prefer seasoned match.
    if (args.season_id) {
      const seasoned = await this.ormRepo.findOne({
        where: { ...baseWhere, season_id: args.season_id },
      });
      if (seasoned) return seasoned;
    }
    // Fall back to the all-season default row.
    return this.ormRepo.findOne({
      where: { ...baseWhere, season_id: IsNull() },
    });
  }

  async findBySupplier(supplier_id: string) {
    const tenantId = this.getTenantId();
    return this.ormRepo.find({
      where: { tenant_id: tenantId, is_deleted: false, supplier_id },
      relations: {
        transport_service: true,
        vehicle_type: true,
        season: true,
        currency: true,
      },
      order: { created_at: 'DESC' },
    });
  }
}
