package de.avatic.lcc.service.bulk.bulkImport;

import de.avatic.lcc.model.excel.ExcelPackaging;
import de.avatic.lcc.model.bulk.BulkInstruction;
import de.avatic.lcc.model.bulk.BulkInstructionType;
import de.avatic.lcc.model.db.packaging.Packaging;
import de.avatic.lcc.model.db.packaging.PackagingType;
import de.avatic.lcc.model.db.properties.PackagingPropertyMappingId;
import de.avatic.lcc.repositories.MaterialRepository;
import de.avatic.lcc.repositories.NodeRepository;
import de.avatic.lcc.repositories.packaging.PackagingDimensionRepository;
import de.avatic.lcc.repositories.packaging.PackagingPropertiesRepository;
import de.avatic.lcc.repositories.packaging.PackagingRepository;
import de.avatic.lcc.service.access.PropertyValidationService;
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
import org.springframework.stereotype.Service;

@Service
public class PackagingBulkImportService {


    private final PackagingRepository packagingRepository;
    private final MaterialRepository materialRepository;
    private final NodeRepository nodeRepository;
    private final PackagingDimensionRepository packagingDimensionRepository;

    private final DimensionTransformer dimensionTransformer;
    private final PackagingPropertiesRepository packagingPropertiesRepository;
    private final PropertyValidationService propertyValidationService;

    public PackagingBulkImportService(PackagingRepository packagingRepository, MaterialRepository materialRepository, NodeRepository nodeRepository, PackagingDimensionRepository packagingDimensionRepository, DimensionTransformer dimensionTransformer, PackagingPropertiesRepository packagingPropertiesRepository, PropertyValidationService propertyValidationService) {
        this.packagingRepository = packagingRepository;
        this.materialRepository = materialRepository;
        this.nodeRepository = nodeRepository;
        this.packagingDimensionRepository = packagingDimensionRepository;
        this.dimensionTransformer = dimensionTransformer;
        this.packagingPropertiesRepository = packagingPropertiesRepository;
        this.propertyValidationService = propertyValidationService;
    }

    public void processPackagingInstructions(BulkInstruction<ExcelPackaging> instr) {
        BulkInstructionType instrType = instr.getType();
        ExcelPackaging excelPackaging = instr.getEntity();


        if (instrType == BulkInstructionType.UPDATE) {
            updatePackaging(excelPackaging);
        } else if (instrType == BulkInstructionType.DELETE) {
            deletePackaging(excelPackaging);
        }

    }

    private void deletePackaging(ExcelPackaging excelPackaging) {
        var material = materialRepository.getByPartNumber(excelPackaging.getPartNumber());
        var supplier = nodeRepository.getByExternalMappingId(excelPackaging.getSupplierMappingId());

        if (material.isEmpty() || supplier.isEmpty()) {
            throw new ExcelValidationError("Packaging references non existing supplier \"" + excelPackaging.getSupplierMappingId() + "\" and/or material \"" + excelPackaging.getPartNumber() + "\"");
        } else {
            packagingRepository.getByMaterialIdAndSupplierId(material.get().getId(), supplier.get().getId()).ifPresent(packaging -> packagingRepository.setDeprecatedById(packaging.getId()));
        }

    }

    private void updatePackaging(ExcelPackaging excelPackaging) {
        var material = materialRepository.getByPartNumber(excelPackaging.getPartNumber());
        var supplier = nodeRepository.getByExternalMappingId(excelPackaging.getSupplierMappingId());

        if (material.isEmpty() || supplier.isEmpty()) {
            throw new ExcelValidationError("Packaging references non existing supplier \"" + excelPackaging.getSupplierMappingId() + "\" and/or material \"" + excelPackaging.getPartNumber() + "\"");
        } else {
            var excelHu = dimensionTransformer.toDimensionEntity(excelPackaging, PackagingType.HU);
            var excelShu = dimensionTransformer.toDimensionEntity(excelPackaging, PackagingType.SHU);

            var packaging = packagingRepository.getByMaterialIdAndSupplierId(material.get().getId(), supplier.get().getId());

            if (packaging.isEmpty()) {
                var huId = packagingDimensionRepository.insert(excelHu).orElseThrow();
                var shuId = packagingDimensionRepository.insert(excelShu).orElseThrow();

                var convertedPackaging = new Packaging();
                convertedPackaging.setMaterialId(material.get().getId());
                convertedPackaging.setSupplierId(supplier.get().getId());
                convertedPackaging.setDeprecated(false);
                convertedPackaging.setHuId(huId);
                convertedPackaging.setShuId(shuId);

                packagingRepository.insert(convertedPackaging);

            } else {
                var hu = packaging.flatMap(o -> packagingDimensionRepository.getById(o.getHuId()));
                var shu = packaging.flatMap(o -> packagingDimensionRepository.getById(o.getShuId()));

                excelHu.setId(hu.isEmpty() ? packagingDimensionRepository.insert(excelHu).orElseThrow() : hu.get().getId());
                excelShu.setId(shu.isEmpty() ? packagingDimensionRepository.insert(excelShu).orElseThrow() : shu.get().getId());

                var convertedPackaging = new Packaging();
                convertedPackaging.setMaterialId(material.get().getId());
                convertedPackaging.setSupplierId(supplier.get().getId());
                convertedPackaging.setDeprecated(false);
                convertedPackaging.setHuId(excelHu.getId());
                convertedPackaging.setShuId(excelShu.getId());
                convertedPackaging.setId(packaging.get().getId());

                if (hu.isPresent())
                    packagingDimensionRepository.update(excelHu);

                if (shu.isPresent())
                    packagingDimensionRepository.update(excelShu);

                for (var mappingId : excelPackaging.getProperties().keySet()) {
                    var id = packagingPropertiesRepository.getTypeIdByMappingId(mappingId);
                    propertyValidationService.validatePackagingProperty(id, PackagingPropertyMappingId.valueOf(mappingId), excelPackaging.getProperties().get(mappingId));
                    packagingPropertiesRepository.update(convertedPackaging.getId(), id, excelPackaging.getProperties().get(mappingId));
                }

                packagingRepository.update(convertedPackaging);
            }
        }

    }
}
