package de.avatic.lcc.service.transformer.material;

import de.avatic.lcc.dto.configuration.material.view.MaterialDetailPackagingDTO;
import de.avatic.lcc.model.db.nodes.Node;
import de.avatic.lcc.model.db.packaging.Packaging;
import de.avatic.lcc.model.db.packaging.PackagingDimension;
import de.avatic.lcc.model.db.properties.PackagingProperty;
import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository;
import de.avatic.lcc.repositories.packaging.PackagingPropertiesRepository;
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
 * Transformer service to convert {@link Packaging} entities into {@link MaterialDetailPackagingDTO} objects.
 * This service includes logic for mapping associated supplier, dimensions, and properties.
 */
@Service
public class MaterialDetailPackagingTransformer {

    private final NodeRepository nodeRepository;
    private final PackagingDimensionRepository packagingDimensionRepository;
    private final DimensionTransformer dimensionTransformer;
    private final NodeTransformer nodeTransformer;
    private final PackagingPropertiesRepository packagingPropertiesRepository;
    private final MaterialDetailPackagingPropertyTransformer materialDetailPackagingPropertyTransformer;

    /**
     * Constructs a MaterialDetailPackagingTransformer with required dependencies.
     *
     * @param nodeRepository                             Repository for managing {@link Node} entities
     * @param packagingDimensionRepository               Repository for managing {@link PackagingDimension} entities
     * @param dimensionTransformer                       Transformer for converting dimensions into DTOs
     * @param nodeTransformer                            Transformer for converting nodes into DTOs
     * @param packagingPropertiesRepository              Repository for managing packaging properties
     * @param materialDetailPackagingPropertyTransformer Transformer for converting packaging properties into DTOs
     */
    public MaterialDetailPackagingTransformer(NodeRepository nodeRepository, PackagingDimensionRepository packagingDimensionRepository, DimensionTransformer dimensionTransformer, NodeTransformer nodeTransformer, PackagingPropertiesRepository packagingPropertiesRepository, MaterialDetailPackagingPropertyTransformer materialDetailPackagingPropertyTransformer) {
        this.nodeRepository = nodeRepository;
        this.packagingDimensionRepository = packagingDimensionRepository;
        this.dimensionTransformer = dimensionTransformer;
        this.nodeTransformer = nodeTransformer;
        this.packagingPropertiesRepository = packagingPropertiesRepository;
        this.materialDetailPackagingPropertyTransformer = materialDetailPackagingPropertyTransformer;
    }

    /**
     * Converts a {@link Packaging} entity into a {@link MaterialDetailPackagingDTO}.
     *
     * @param entity The {@link Packaging} entity to transform
     * @return The transformed {@link MaterialDetailPackagingDTO} object
     * @throws java.util.NoSuchElementException if any referenced related entity is not found
     */
    public MaterialDetailPackagingDTO toMaterialViewPackagingDTO(Packaging entity) {
        Optional<Node> supplier = nodeRepository.getById(entity.getSupplierId());
        Optional<PackagingDimension> hu = packagingDimensionRepository.getById(entity.getHuId());
        Optional<PackagingDimension> shu = packagingDimensionRepository.getById(entity.getShuId());
        List<PackagingProperty> properties = packagingPropertiesRepository.getByPackagingId(entity.getId());

        MaterialDetailPackagingDTO dto = new MaterialDetailPackagingDTO();
        dto.setId(entity.getId());
        dto.setDeprecated(entity.getDeprecated());
        dto.setHu(dimensionTransformer.toDimensionDTO(hu.orElseThrow()));
        dto.setShu(dimensionTransformer.toDimensionDTO(shu.orElseThrow()));
        dto.setSupplier(nodeTransformer.toNodeDTO(supplier.orElseThrow()));
        dto.setProperties(properties.stream().map(materialDetailPackagingPropertyTransformer::toPropertyDTO).toList());

        return dto;
    }

}
