package com.izouma.zhirongip.service.resource;

import com.izouma.zhirongip.converter.StringArrayConverter;
import com.izouma.zhirongip.domain.Setting;
import com.izouma.zhirongip.domain.resource.Company;
import com.izouma.zhirongip.domain.resource.NumOfIp;
import com.izouma.zhirongip.dto.CompanyDTO;
import com.izouma.zhirongip.dto.PageQuery;
import com.izouma.zhirongip.exception.BusinessException;
import com.izouma.zhirongip.repo.SettingRepo;
import com.izouma.zhirongip.repo.resource.CompanyRepo;
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.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.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class CompanyService {

    private final CompanyRepo companyRepo;
    private final SettingRepo settingRepo;

    public Page<Company> excelAll(PageQuery pageQuery) {
        return companyRepo.findAll(JpaUtils.toSpecification(pageQuery, Company.class), JpaUtils.toPageRequest(pageQuery));
    }

    public Page<Company> all(PageQuery pageQuery) {
        Map<Long, String> settingMap = settingRepo.findAll().stream()
                .collect(Collectors.toMap(Setting::getId, Setting::getName));
        return companyRepo.findAll(JpaUtils.toSpecification(pageQuery, Company.class), JpaUtils.toPageRequest(pageQuery))
                .map(cd -> {
                    cd.setFieldName(settingMap.get(cd.getField()));
                    cd.setSettingName(settingMap.get(cd.getSettingId()));
                    return cd;
                });
    }

    public Company get(Long id) {
        Company company = companyRepo.findById(id).orElseThrow(new BusinessException("无记录"));
        List<Long> ids = new ArrayList<>();
        ids.add(company.getField());
        ids.add(company.getSettingId());
        Map<Long, String> settingMap = settingRepo.findAllById(ids)
                .stream()
                .collect(Collectors.toMap(Setting::getId, Setting::getName));
        company.setFieldName(settingMap.get(company.getField()));
        company.setSettingName(settingMap.get(company.getSettingId()));
        return company;
    }

    public List<CompanyDTO> toDtoList(List<Company> companies) {
        List<CompanyDTO> dtos = new ArrayList<>();
        Map<Long, String> settingMap = settingRepo.findAll().stream()
                .collect(Collectors.toMap(Setting::getId, Setting::getName));
        companies.forEach(company -> {
            CompanyDTO dto = new CompanyDTO(company);
            dto.setSettingName(settingMap.get(company.getSettingId()));
            dto.setFieldName(settingMap.get(company.getField()));
            dto.setNetworkName(company.getNetwork().stream().map(settingMap::get).collect(Collectors.joining(",")));
            dto.setConfidentialityLevelName(settingMap.get(company.getConfidentialityLevel()));
            dto.setUnitLevelName(settingMap.get(company.getUnitLevel()));
            dto.setProductionLevelName(settingMap.get(company.getProductionLevel()));
            dto.setIntegrationLevelName(settingMap.get(company.getIntegrationLevel()));
            dto.setNumOfIpsName(company.getNumOfIps()
                    .stream()
                    .map(num -> num.getContent(settingMap.get(num.getIp())))
                    .collect(Collectors.joining()));
            dto.setStandardizationLevelName(company.getStandardizationLevel()
                    .stream()
                    .map(settingMap::get)
                    .collect(Collectors.joining(",")));
            dto.setQualificationLevelName(company.getQualificationLevel()
                    .stream()
                    .map(settingMap::get)
                    .collect(Collectors.joining(",")));
            dtos.add(dto);
        });
        return dtos;
    }

    /*
     导入
     */
    @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<CompanyDTO> dtos =
                ExcelUtils.readExcel(indicatorStream, CompanyDTO.class, 1, 1);

        List<Company> records = new ArrayList<>();
        List<Setting> settings = settingRepo.findAll();
        Map<Integer, List<Setting>> listMap = settings
                .stream()
                .collect(Collectors.groupingBy(Setting::getFlag));
        Map<Integer, Map<String, Long>> mapMap = settings
                .stream()
                .collect(Collectors.groupingBy(Setting::getFlag, Collectors.toMap(Setting::getName, Setting::getId)));

        dtos.forEach(dto -> {
            Company company = new Company(dto);

            StringArrayConverter sc = new StringArrayConverter();

            company.setField(mapMap.get(1).get(dto.getFieldName()));

            company.setSettingId(mapMap.get(11).get(dto.getSettingName()));

            company.setNetwork(listMap.get(16)
                    .stream()
                    .filter(list -> sc.convertToEntityAttribute(dto.getNetworkName()).contains(list.getName()))
                    .map(Setting::getId)
                    .collect(Collectors.toList()));

            company.setConfidentialityLevel(mapMap.get(17).get(dto.getConfidentialityLevelName()));

            company.setUnitLevel(mapMap.get(18).get(dto.getUnitLevelName()));

            company.setProductionLevel(mapMap.get(19).get(dto.getProductionLevelName()));

            company.setIntegrationLevel(mapMap.get(20).get(dto.getIntegrationLevelName()));

            List<String> nums = Arrays.asList(dto.getNumOfIpsName().split(";"));
            Map<String, Long> ipMap = listMap.get(21)
                    .stream()
                    .collect(Collectors.toMap(Setting::getName, Setting::getId));
            List<NumOfIp> numOfIps = new ArrayList<>();
            nums.forEach(num -> {
                String[] split = num.split(":");
                Long id = ipMap.get(split[0]);
                numOfIps.add(new NumOfIp(id, Integer.parseInt(split[1])));
            });
            company.setNumOfIps(numOfIps);

            company.setStandardizationLevel(listMap.get(22)
                    .stream()
                    .filter(list -> sc.convertToEntityAttribute(dto.getStandardizationLevelName()).contains(list.getName()))
                    .map(Setting::getId)
                    .collect(Collectors.toList()));

            company.setQualificationLevel(listMap.get(23)
                    .stream()
                    .filter(list -> sc.convertToEntityAttribute(dto.getQualificationLevelName()).contains(list.getName()))
                    .map(Setting::getId)
                    .collect(Collectors.toList()));

            records.add(company);
        });

        companyRepo.saveAll(records);
    }
}
