package io.delphiplatform.api.v3.rdb.service;

import com.google.common.collect.ImmutableMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import io.delphiplatform.api.v3.model.gras.ProductVersion;
import io.delphiplatform.api.v3.rdb.entity.ProductVersionEntity;
import io.delphiplatform.api.v3.rdb.repository.ProductVersionRepository;
import io.delphiplatform.api.v3.rdb.service.specification.SpecificationProvider;
import io.delphiplatform.api.v3.view.util.Params;

@Service
public class ProductVersionService extends EntityService<ProductVersionEntity> {

    private static final Set<String> FETCHES = Set.of("configurationCategory", "productClass",
        "repertoireOwner", "label", "mainArtist");

    private static final ImmutableMap<String, String> SORT_BY_TO_ENTITY_FIELD_MAP = ImmutableMap.<String, String>builder()
        .put("config_cat_key", "configuration_category_config_cat_key")
        .put("config_cat_name", "configuration_category_config_cat_name")
        .put("is_product_family_head", "is_prod_fam_head")
        .put("label_id", "label_label_id")
        .put("main_artist_id", "main_artist_artist_id")
        .put("product_class_key", "product_class_prod_class_key")
        .put("product_class_name", "product_class_prod_class_name")
        .put("product_family_no", "prod_fam_no")
        .put("product_title", "prod_title")
        .put("product_title_suppl", "prod_title_suppl")
        .put("product_version_no", "prod_vers_no")
        .put("rep_owner_key", "repertoire_owner_rep_owner_key")
        .build();

    private final ProductVersionRepository productVersionRepository;
    private final SpecificationProvider<ProductVersionEntity> specificationProvider;

    @Autowired
    public ProductVersionService(ProductVersionRepository productVersionRepository,
        SpecificationProvider<ProductVersionEntity> specificationProvider) {
        super(productVersionRepository, SORT_BY_TO_ENTITY_FIELD_MAP);
        this.specificationProvider = specificationProvider;
        this.productVersionRepository = productVersionRepository;
    }


    @Transactional(readOnly = true)
    public ProductVersion findOne(Integer productVersionNo) {
        return productVersionRepository.findById(productVersionNo)
            .map(ProductVersion::from)
            .orElseThrow(NOT_FOUND);
    }

    @Transactional(readOnly = true)
    public List<ProductVersion> find(Params params) {

        Specification<ProductVersionEntity> specification = and(Arrays.asList(
            specificationProvider.singleValueSpec("isProdFamHead", params.getIsProductFamilyHead()),
            specificationProvider.singleValueSpec("prodFamNo", params.getProductFamilyNo()),
            specificationProvider.singleValueSpec("productId", params.getProductId(), "products"),
            specificationProvider.singleValueSpec("projectId", params.getProjectId(), "projects"),
            specificationProvider.multiValueSpec("repOwnerKey", params.getRepOwnerKey(), "repertoireOwner"),
            specificationProvider.singleValueSpec("configCatKey", params.getConfigCatKey(), "configurationCategory"),
            specificationProvider
                .singleValueSpec("configKey", params.getConfigKey(), List.of("products", "configuration")),

            specificationProvider.fetchesSpec(FETCHES)
        ));

        return find(specification, getPageRequestSortByToCamelCase(params))
            .stream()
            .map(ProductVersion::from)
            .collect(Collectors.toList());
    }
}
