/**
 * TypeORM RateQuote Repository
 *
 * Implements RateQuoteRepository interface using TypeORM
 */

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, LessThan } from 'typeorm';
import { RateQuote } from '@domain/entities/rate-quote.entity';
import { RateQuoteRepository } from '@domain/ports/out/rate-quote.repository';
import { RateQuoteOrmEntity } from '../entities/rate-quote.orm-entity';
import { RateQuoteOrmMapper } from '../mappers/rate-quote-orm.mapper';

@Injectable()
export class TypeOrmRateQuoteRepository implements RateQuoteRepository {
  constructor(
    @InjectRepository(RateQuoteOrmEntity)
    private readonly repository: Repository<RateQuoteOrmEntity>
  ) {}

  async save(rateQuote: RateQuote): Promise<RateQuote> {
    const orm = RateQuoteOrmMapper.toOrm(rateQuote);
    const saved = await this.repository.save(orm);
    return RateQuoteOrmMapper.toDomain(saved);
  }

  async saveMany(rateQuotes: RateQuote[]): Promise<RateQuote[]> {
    const orms = rateQuotes.map(rq => RateQuoteOrmMapper.toOrm(rq));
    const saved = await this.repository.save(orms);
    return RateQuoteOrmMapper.toDomainMany(saved);
  }

  async findById(id: string): Promise<RateQuote | null> {
    const orm = await this.repository.findOne({ where: { id } });
    return orm ? RateQuoteOrmMapper.toDomain(orm) : null;
  }

  async findBySearchCriteria(criteria: {
    origin: string;
    destination: string;
    containerType: string;
    departureDate: Date;
  }): Promise<RateQuote[]> {
    const startOfDay = new Date(criteria.departureDate);
    startOfDay.setHours(0, 0, 0, 0);
    const endOfDay = new Date(criteria.departureDate);
    endOfDay.setHours(23, 59, 59, 999);

    const orms = await this.repository
      .createQueryBuilder('rq')
      .where('rq.origin_code = :origin', { origin: criteria.origin.toUpperCase() })
      .andWhere('rq.destination_code = :destination', {
        destination: criteria.destination.toUpperCase(),
      })
      .andWhere('rq.container_type = :containerType', { containerType: criteria.containerType })
      .andWhere('rq.etd >= :startOfDay', { startOfDay })
      .andWhere('rq.etd <= :endOfDay', { endOfDay })
      .andWhere('rq.valid_until > :now', { now: new Date() })
      .orderBy('rq.total_amount', 'ASC')
      .getMany();

    return RateQuoteOrmMapper.toDomainMany(orms);
  }

  async findByCarrier(carrierId: string): Promise<RateQuote[]> {
    const orms = await this.repository.find({
      where: { carrierId },
      order: { createdAt: 'DESC' },
    });
    return RateQuoteOrmMapper.toDomainMany(orms);
  }

  async deleteExpired(): Promise<number> {
    const result = await this.repository.delete({
      validUntil: LessThan(new Date()),
    });
    return result.affected || 0;
  }

  async deleteById(id: string): Promise<void> {
    await this.repository.delete({ id });
  }
}
