import { Injectable } from '@nestjs/common';
import { CsvRate } from '@domain/entities/csv-rate.entity';
import { Volume } from '@domain/value-objects/volume.vo';
import { CsvRateResultDto, CsvRateSearchResponseDto } from '../dto/csv-rate-search.dto';
import {
  CsvRateSearchInput,
  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';

/**
 * CSV Rate Mapper
 *
 * Maps between domain entities and DTOs
 * Follows hexagonal architecture principles
 */
@Injectable()
export class CsvRateMapper {
  /**
   * Map DTO filters to domain filters
   */
  mapFiltersDtoToDomain(dto?: RateSearchFiltersDto): RateSearchFilters | undefined {
    if (!dto) {
      return undefined;
    }

    return {
      companies: dto.companies,
      minVolumeCBM: dto.minVolumeCBM,
      maxVolumeCBM: dto.maxVolumeCBM,
      minWeightKG: dto.minWeightKG,
      maxWeightKG: dto.maxWeightKG,
      palletCount: dto.palletCount,
      minPrice: dto.minPrice,
      maxPrice: dto.maxPrice,
      currency: dto.currency,
      minTransitDays: dto.minTransitDays,
      maxTransitDays: dto.maxTransitDays,
      containerTypes: dto.containerTypes,
      onlyAllInPrices: dto.onlyAllInPrices,
      departureDate: dto.departureDate ? new Date(dto.departureDate) : undefined,
    };
  }

  /**
   * Map domain search result to DTO
   */
  mapSearchResultToDto(result: CsvRateSearchResult): CsvRateResultDto {
    const rate = result.rate;

    return {
      companyName: rate.companyName,
      companyEmail: rate.companyEmail,
      origin: rate.origin.getValue(),
      destination: rate.destination.getValue(),
      containerType: rate.containerType.getValue(),
      priceUSD: result.calculatedPrice.usd,
      priceEUR: result.calculatedPrice.eur,
      primaryCurrency: result.calculatedPrice.primaryCurrency,
      priceBreakdown: {
        basePrice: result.priceBreakdown.basePrice,
        volumeCharge: result.priceBreakdown.volumeCharge,
        weightCharge: result.priceBreakdown.weightCharge,
        palletCharge: result.priceBreakdown.palletCharge,
        surcharges: result.priceBreakdown.surcharges.map(s => ({
          code: s.code,
          description: s.description,
          amount: s.amount,
          type: s.type,
        })),
        totalSurcharges: result.priceBreakdown.totalSurcharges,
        totalPrice: result.priceBreakdown.totalPrice,
        currency: result.priceBreakdown.currency,
      },
      hasSurcharges: rate.hasSurcharges(),
      surchargeDetails: rate.hasSurcharges() ? rate.getSurchargeDetails() : null,
      transitDays: rate.transitDays,
      validUntil: rate.validity.getEndDate().toISOString().split('T')[0],
      source: result.source,
      matchScore: result.matchScore,
    };
  }

  /**
   * Map domain search output to response DTO
   */
  mapSearchOutputToResponseDto(output: CsvRateSearchOutput): CsvRateSearchResponseDto {
    return {
      results: output.results.map(result => this.mapSearchResultToDto(result)),
      totalResults: output.totalResults,
      searchedFiles: output.searchedFiles,
      searchedAt: output.searchedAt,
      appliedFilters: output.appliedFilters as any, // Already matches DTO structure
    };
  }

  /**
   * Map ORM entity to DTO
   */
  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,
    };
  }

  /**
   * Map multiple config entities to DTOs
   */
  mapConfigEntitiesToDtos(entities: CsvRateConfigOrmEntity[]): CsvRateConfigDto[] {
    return entities.map(entity => this.mapConfigEntityToDto(entity));
  }
}
