package com.izouma.zhirongip.service.resource;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.izouma.zhirongip.converter.StringArrayConverter;
import com.izouma.zhirongip.domain.Setting;
import com.izouma.zhirongip.domain.resource.Expert;
import com.izouma.zhirongip.dto.ExpertDTO;
import com.izouma.zhirongip.dto.PageQuery;
import com.izouma.zhirongip.exception.BusinessException;
import com.izouma.zhirongip.repo.SettingRepo;
import com.izouma.zhirongip.repo.resource.ExpertRepo;
import com.izouma.zhirongip.utils.JpaUtils;
import com.izouma.zhirongip.utils.excel.ExcelUtils;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class ExpertService {

    private final ExpertRepo  expertRepo;
    private final SettingRepo settingRepo;

    public Page<Expert> all(PageQuery pageQuery, Long field) {
        Map<Long, String> settingMap = settingRepo.findAllByFlagIn(CollUtil.newArrayList(1, 15))
                .stream()
                .collect(Collectors.toMap(Setting::getId, Setting::getName));

        return expertRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> and = JpaUtils.toPredicates(pageQuery, Expert.class, root, criteriaQuery, criteriaBuilder);
                    if (ObjectUtil.isNotNull(field)) {
                        Expression<Long> function = criteriaBuilder.function("FIND_IN_SET", Long.class, criteriaBuilder.literal(field), root
                                .get("field"));
                        and.add(criteriaBuilder.greaterThan(function, 0L));
                    }

                    return criteriaBuilder.and(and.toArray(new Predicate[0]));
                }), JpaUtils.toPageRequest(pageQuery))
                .map(manager -> {
                    List<String> names = manager.getField()
                            .stream()
                            .map(settingMap::get)
                            .collect(Collectors.toList());
                    manager.setFieldName(names);
                    manager.setFieldNames(String.join(",", names));
                    manager.setAffiliationName(settingMap.get(manager.getAffiliation()));
                    return manager;
                });
    }

    public Expert get(Long id) {

        Map<Long, String> settingMap = settingRepo.findAllByFlagIn(CollUtil.newArrayList(1, 15))
                .stream()
                .collect(Collectors.toMap(Setting::getId, Setting::getName));
        Expert expert = expertRepo.findById(id).orElseThrow(new BusinessException("无记录"));
        expert.setFieldName(expert.getField()
                .stream()
                .map(settingMap::get)
                .collect(Collectors.toList()));
        expert.setAffiliationName(settingMap.get(expert.getAffiliation()));
        return expert;
    }

    /*
    导入
    */
    @Transactional(rollbackOn = Exception.class)
    public void upload(InputStream is) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) > -1) {
            baos.write(buffer, 0, len);
        }
        baos.flush();

        InputStream indicatorStream = new ByteArrayInputStream(baos.toByteArray());
        List<ExpertDTO> dtos =
                ExcelUtils.readExcel(indicatorStream, ExpertDTO.class, 1, 1);

//        List<Expert> experts = dtos.stream().map(Expert::new).collect(Collectors.toList());
        List<Expert> experts = new ArrayList<>();
        List<Setting> settings = settingRepo.findAllByFlagIn(CollUtil.newArrayList(1, 15));
        dtos.forEach(dto -> {
            Expert expert = new Expert(dto);
            if (StrUtil.isNotBlank(dto.getFieldNames())) {
                StringArrayConverter sc = new StringArrayConverter();
                List<String> names = sc.convertToEntityAttribute(dto.getFieldNames());
                expert.setField(settings.stream()
                        .filter(setting -> setting.getFlag() == 1 && names.contains(setting.getName()))
                        .map(Setting::getId)
                        .collect(Collectors.toList()));
            }
            settings.stream()
                    .filter(setting -> setting.getFlag() == 15 && setting.getName()
                            .equals(dto.getAffiliationName()))
                    .findFirst()
                    .ifPresent(setting -> expert.setAffiliation(setting.getId()));
            experts.add(expert);
        });
        expertRepo.saveAll(experts);

    }
}
