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.RepertoireOwner;
import io.delphiplatform.api.v3.rdb.entity.RepertoireOwnerEntity;
import io.delphiplatform.api.v3.rdb.repository.RepertoireOwnerRepository;
import io.delphiplatform.api.v3.rdb.service.specification.SpecificationProvider;
import io.delphiplatform.api.v3.view.util.Params;

@Service
@Transactional(readOnly = true)
public class RepertoireOwnerService extends EntityService<RepertoireOwnerEntity> {

    private static final Set<String> FETCHES = Set.of("profitCenter", "repertoireOwnerCompany", "label");

    private static final ImmutableMap<String, String> SORT_BY_TO_ENTITY_FIELD_MAP = ImmutableMap.<String, String>builder()
        .put("is_product_rep_owner", "is_prod_rep_owner")
        .put("is_project_rep_owner", "is_rec_project_rep_owner")
        .put("label_id", "label_label_id")
        .put("profit_center_key", "profit_center_profit_center_key")
        .put("parent_rep_owner_key", "profit_center_parent_repertoire_owner_parent_rep_owner_key")
        .build();

    private final RepertoireOwnerRepository repertoireOwnerRepository;
    private final SpecificationProvider<RepertoireOwnerEntity> specificationProvider;

    @Autowired
    public RepertoireOwnerService(RepertoireOwnerRepository repertoireOwnerRepository,
        SpecificationProvider<RepertoireOwnerEntity> specificationProvider) {
        super(repertoireOwnerRepository, SORT_BY_TO_ENTITY_FIELD_MAP);
        this.specificationProvider = specificationProvider;
        this.repertoireOwnerRepository = repertoireOwnerRepository;
    }


    public RepertoireOwner findOne(String projectId) {
        return repertoireOwnerRepository.findById(projectId)
            .map(RepertoireOwner::from)
            .orElseThrow(NOT_FOUND);
    }

    public List<RepertoireOwner> find(Params params) {
        Specification<RepertoireOwnerEntity> specification = and(Arrays.asList(
            specificationProvider.multiValueSpec("profitCenterKey", params.getProfitCenterKeys(), "profitCenter"),
            specificationProvider.multiValueSpec("parentRepOwnerKey", params.getParentRepOwnerKeys(),
                Arrays.asList("profitCenter", "parentRepertoireOwner")),
            specificationProvider.singleValueSpec("labelId", params.getLabelId(), "label"),

            specificationProvider.fetchesSpec(FETCHES)
        ));

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

}
