import { Injectable } from '@nestjs/common';
import {
  CsvRateResultDto,
  CsvRateSearchResponseDto,
  PriceBreakdownDto,
  FobBreakdownDto,
} from '../dto/csv-rate-search.dto';
import {
  CsvRateSearchOutput,
  CsvRateSearchResult,
  RateSearchFilters,
} from '@domain/ports/in/search-csv-rates.port';
import { RateSearchFiltersDto } from '../dto/rate-search-filters.dto';
import { CsvRateConfigDto } from '../dto/csv-rate-upload.dto';
import { CsvRateConfigOrmEntity } from '@infrastructure/persistence/typeorm/entities/csv-rate-config.orm-entity';

@Injectable()
export class CsvRateMapper {
  mapFiltersDtoToDomain(dto?: RateSearchFiltersDto): RateSearchFilters | undefined {
    if (!dto) return undefined;
    return {
      companies: dto.companies,
      onlyDirect: dto.onlyDirect,
      excludeNonDgRoutes: dto.excludeNonDgRoutes,
      minPrice: dto.minPrice,
      maxPrice: dto.maxPrice,
      currency: dto.currency,
      minTransitDays: dto.minTransitDays,
      maxTransitDays: dto.maxTransitDays,
      containerTypes: dto.containerTypes,
      departureDate: dto.departureDate ? new Date(dto.departureDate) : undefined,
    };
  }

  mapSearchResultToDto(result: CsvRateSearchResult): CsvRateResultDto {
    const rate = result.rate;
    const bd = result.priceBreakdown;

    const fobBreakdown: FobBreakdownDto = {
      documentation: bd.fobBreakdown.documentation,
      isps: bd.fobBreakdown.isps,
      handling: bd.fobBreakdown.handling,
      solas: bd.fobBreakdown.solas,
      customs: bd.fobBreakdown.customs,
      ams_aci: bd.fobBreakdown.ams_aci,
      isf5: bd.fobBreakdown.isf5,
      dgAdmin: bd.fobBreakdown.dgAdmin,
    };

    const priceBreakdown: PriceBreakdownDto = {
      freightCharge: bd.freightCharge,
      freightCurrency: bd.freightCurrency,
      fobFixed: bd.fobFixed,
      fobHandling: bd.fobHandling,
      fobDG: bd.fobDG,
      fobCurrency: bd.fobCurrency,
      fobBreakdown,
      dgSurchargeAmount: bd.dgSurchargeAmount,
      dgSurchargeCurrency: bd.dgSurchargeCurrency,
      dgSurchargeStatus: bd.dgSurchargeStatus,
      totalFreight: bd.totalFreight,
      totalFob: bd.totalFob,
      totalPriceForSorting: bd.totalPriceForSorting,
      primaryCurrency: bd.primaryCurrency,
    };

    return {
      companyName: rate.companyName,
      companyEmail: rate.companyEmail,
      originCFS: rate.originCFS,
      origin: rate.originCode.getValue(),
      portOfLoading: rate.portOfLoading,
      routing: rate.routing,
      destinationCFS: rate.destinationCFS,
      destination: rate.destinationCode.getValue(),
      destinationCountry: rate.destinationCountry,
      containerType: rate.containerType.getValue(),
      priceBreakdown,
      frequency: rate.frequency,
      transitDays: result.adjustedTransitDays ?? rate.transitDays,
      validUntil: rate.validity.getEndDate().toISOString().split('T')[0],
      dgAccepted: rate.isDgAccepted(),
      dgSurchargeStatus: bd.dgSurchargeStatus,
      remarks: rate.remarks,
      source: result.source,
      matchScore: result.matchScore,
      serviceLevel: result.serviceLevel,
      priceMultiplier: result.priceMultiplier,
      originalTransitDays: result.originalTransitDays,
    };
  }

  mapSearchOutputToResponseDto(output: CsvRateSearchOutput): CsvRateSearchResponseDto {
    return {
      results: output.results.map(r => this.mapSearchResultToDto(r)),
      totalResults: output.totalResults,
      searchedFiles: output.searchedFiles,
      searchedAt: output.searchedAt,
      appliedFilters: output.appliedFilters as any,
    };
  }

  mapConfigEntityToDto(entity: CsvRateConfigOrmEntity): CsvRateConfigDto {
    return {
      id: entity.id,
      companyName: entity.companyName,
      csvFilePath: entity.csvFilePath,
      type: entity.type,
      hasApi: entity.hasApi,
      apiConnector: entity.apiConnector,
      isActive: entity.isActive,
      uploadedAt: entity.uploadedAt,
      rowCount: entity.rowCount,
      metadata: entity.metadata,
    };
  }

  mapConfigEntitiesToDtos(entities: CsvRateConfigOrmEntity[]): CsvRateConfigDto[] {
    return entities.map(e => this.mapConfigEntityToDto(e));
  }
}
