package com.zjty.inspect.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zjty.inspect.dao.RuleCollectionDao;
import com.zjty.inspect.dao.RuleDao;
import com.zjty.inspect.entity.*;
import com.zjty.inspect.service.RuleService;
import com.zjty.inspect.service.TechnologyService;
import com.zjty.inspect.utils.FileUtil;
import com.zjty.inspect.utils.UUIDUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.io.*;
import java.io.File;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * 规则库
 *
 * @author Mcj
 * @date 2020-02-26 15:05
 */

@Service
@Transactional(rollbackFor = Exception.class)
public class RuleServiceImpl implements RuleService {

    /**
     * 规则库dao
     */
    @Autowired
    private RuleDao ruleDao;

    @Autowired
    private TechnologyService technologyService;
    @Autowired
    private RuleCollectionDao ruleCollectionDao;

    @Override
    public List<Rule> findRules() {
        List<Rule> rules = ruleDao.findAll();
        List<Rule> ruleList = new ArrayList<>();
        if (rules != null && rules.size() > 0) {
            for (Rule rule : rules) {
                String suffix = rule.getSuffix();
                String[] split = suffix.split(",");
                for (String s : split) {
                    Rule rule1 = new Rule();
                    BeanUtils.copyProperties(rule, rule1);
                    rule1.setSuffix(s);
                    ruleList.add(rule1);
                }
            }
        }
        return ruleList;
    }

    @Override
    public Rule addRulePlus(Rule rule) {
        if (StringUtils.isEmpty(rule.getTarget())) {
            return null;
        }
        Rule rule1 = ruleDao.findByTarget(rule.getTarget());
        if (rule1 == null) {
            rule.setId(UUIDUtil.getUUID());
            Rule save = ruleDao.save(rule);
            return save;
        }
        return null;
    }

    /**
     * 新增规则
     *
     * @param ruleQo 规则封装类
     */
    @Override
    public void addRule(RuleQo ruleQo) {
        List<String> suffixes = ruleQo.getSuffix();
        for (String suffix : suffixes) {
            List<Rule> rule1 = ruleDao.findByTargetAndSuffixEqualsAndTechnologyIdEquals(ruleQo.getTarget(), suffix, ruleQo.getTechnologyId());
            if (rule1 != null && rule1.size() > 0) {
                continue;
            }
            Rule rule = new Rule();
            rule.setTarget(ruleQo.getTarget());
            rule.setSuffix(suffix);
            rule.setTechnologyId(ruleQo.getTechnologyId());
            rule.setTechnologyName(ruleQo.getTechnologyName());
            rule.setId(UUIDUtil.getUUID());
            ruleDao.save(rule);
        }
        RuleCollection ruleCollection = dataQo2RuleCollection(ruleQo);
        ruleCollectionDao.save(ruleCollection);

    }


    //批量添加
    @Override
    public void addListRulePlus(List<Rule> rules) {
        for (Rule rule : rules) {
            addRulePlus(rule);
        }
    }

    @Override
    public void addRule(List<Rule> rules) {
        ruleDao.saveAll(rules);
        List<RuleCollection> ruleCollections = dataList2RuleCollection(rules);
        ruleCollectionDao.saveAll(ruleCollections);
    }

    /**
     * 条件查询+分页
     *
     * @param whereMap
     * @param page
     * @param size
     * @return
     */
    @Override
    public Page<Rule> findSearch(Map whereMap, int page, int size) {
        Specification<Rule> specification = createSpecification(whereMap);
        Sort sort = new Sort(Sort.Direction.DESC, "updateDate");
        PageRequest pageRequest = PageRequest.of(page - 1, size, sort);
        return ruleDao.findAll(specification, pageRequest);

    }

    @Override
    public List<Rule> findAllByTechnologyIdIn(List<String> technologyIds) {
        List<Rule> rules = ruleDao.findAllByTechnologyIdIn(technologyIds);
        List<Rule> ruleList = new ArrayList<>();
        if (rules != null && rules.size() > 0) {
            for (Rule rule : rules) {
                String suffix = rule.getSuffix();
                String[] split = suffix.split(",");
                for (String s : split) {
                    Rule rule1 = new Rule();
                    BeanUtils.copyProperties(rule, rule1);
                    rule1.setSuffix(s);
                    ruleList.add(rule1);
                }
            }
        }
        return ruleList;
    }


    /**
     * 动态条件构建
     *
     * @param searchMap
     * @return
     */
    private Specification<Rule> createSpecification(Map searchMap) {

        return new Specification<Rule>() {

            @Override
            public Predicate toPredicate(Root<Rule> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicateList = new ArrayList<Predicate>();
                if (searchMap.get("technologyName") != null && !"".equals(searchMap.get("technologyName"))) {
                    predicateList.add(cb.like(root.get("technologyName").as(String.class), "%" + searchMap.get("technologyName") + "%"));
                }
                if (searchMap.get("target") != null && !"".equals(searchMap.get("target"))) {
                    predicateList.add(cb.like(root.get("target").as(String.class), "%" + searchMap.get("target") + "%"));
                }
                if (searchMap.get("suffix") != null && !"".equals(searchMap.get("suffix"))) {
                    predicateList.add(cb.like(root.get("suffix").as(String.class), "%" + searchMap.get("suffix") + "%"));
                }
                return cb.and( predicateList.toArray(new Predicate[predicateList.size()]));

            }
        };

    }


    @Override
    public void upRule(RuleQo ruleQo) {
        RuleQo oldRule = ruleQo.getOldRule();
        List<Rule> rules = ruleDao.findAllByTechnologyIdEqualsAndTargetEquals(oldRule.getTechnologyId(), oldRule.getTarget());
        RuleCollection ruleCollection = ruleCollectionDao.findAllByTechnologyIdEqualsAndTargetEquals(oldRule.getTechnologyId(), oldRule.getTarget());
        for (Rule rule : rules) {
            ruleDao.deleteById(rule.getId());
        }
        if (ruleCollection != null) {
            ruleCollectionDao.deleteById(ruleCollection.getId());
        }
        addRule(ruleQo);
    }

    @Override
    public void upRulePlus(Rule rule) {
        Rule rule1 = ruleDao.findByTargetAndIdNot(rule.getTarget(), rule.getId());
        if (rule1 == null) {
            ruleDao.save(rule);
        } else {
            ruleDao.deleteById(rule.getId());
        }
    }

    @Override
    public void deleteRulePlus(String id) {
        ruleDao.deleteById(id);
    }


    @Override
    @Modifying
    public void deleteRule(RuleQo ruleQo) {
        List<Rule> rules = ruleDao.findAllByTechnologyIdEqualsAndTargetEquals(ruleQo.getTechnologyId(), ruleQo.getTarget());
        for (Rule rule : rules) {
            ruleDao.deleteById(rule.getId());
        }
        RuleCollection ruleCollection = ruleCollectionDao.findAllByTechnologyIdEqualsAndTargetEquals(ruleQo.getTechnologyId(), ruleQo.getTarget());
        if (ruleCollection != null) {
            ruleCollectionDao.deleteById(ruleCollection.getId());
        }

    }

    /**
     * 查询所有规则
     * 规则唯一 关键字+后缀+技术id
     * target:xx,suffix:js:tech:gjfgj
     * target:xx,suffix:html:tech:gjfgj
     * target:xx,suffix:css:tech:gjfgj
     * <p>
     * target:xx,suffix:html,css,js:tech:gjfgj
     *
     * @return RuleVoList
     */
    @Override
    public List<RuleCollection> findAll() {
        List<RuleCollection> rules = ruleCollectionDao.findAll();
        return rules;
    }

    @Override
    public List<RuleCollection> findByName(String name) {
        List<RuleCollection> rules = ruleCollectionDao.findAllByTargetLike("%" + name + "%");
        return rules;
    }

    private RuleCollection dataQo2RuleCollection(RuleQo ruleQo) {
        RuleCollection ruleCollection = new RuleCollection();
        ruleCollection.setTechnologyName(ruleQo.getTechnologyName());
        ruleCollection.setTechnologyId(ruleQo.getTechnologyId());
        ruleCollection.setTarget(ruleQo.getTarget());
        ruleCollection.setId(UUIDUtil.getUUID());
        StringBuilder stringBuilder = new StringBuilder();
        for (String suffix : ruleQo.getSuffix()) {
            if (stringBuilder.length() == 0) {
                stringBuilder.append(suffix);
            } else {
                stringBuilder.append(",").append(suffix);
            }
        }
        ruleCollection.setSuffix(stringBuilder.toString());
        return ruleCollection;
    }

    private List<RuleCollection> dataList2RuleCollection(List<Rule> rules) {
        ArrayList<RuleCollection> ruleCollections = new ArrayList<>();
        HashMap<String, ArrayList<String>> map = new HashMap<>();
        HashMap<String, Rule> ruleMap = new HashMap<>();
        for (Rule rule : rules) {
            ruleMap.put(rule.getTarget() + ":" + rule.getTechnologyId(), rule);
            if (map.containsKey(rule.getTarget() + ":" + rule.getTechnologyId())) {
                ArrayList<String> suffix = map.get(rule.getTarget() + ":" + rule.getTechnologyId());
                suffix.add(rule.getSuffix());
            } else {
                ArrayList<String> suffix = new ArrayList<>();
                suffix.add(rule.getSuffix());
                map.put(rule.getTarget() + ":" + rule.getTechnologyId(), suffix);
            }
        }

        for (String target : map.keySet()) {
            Rule rule = ruleMap.get(target);
            RuleCollection ruleCollection = new RuleCollection();
            ruleCollection.setTarget(rule.getTarget());
            ruleCollection.setTechnologyId(rule.getTechnologyId());
            ruleCollection.setTechnologyName(rule.getTechnologyName());
            ruleCollection.setId(UUIDUtil.getUUID());
            StringBuilder stringBuilder = new StringBuilder();
            for (String suffix : map.get(target)) {
                if (stringBuilder.length() == 0) {
                    stringBuilder.append(suffix);
                } else {
                    stringBuilder.append(",").append(suffix);
                }
            }
            ruleCollection.setSuffix(stringBuilder.toString());
            ruleCollections.add(ruleCollection);
        }
        return ruleCollections;
    }

    @Override
    public String exportData() {
        SyncData syncData = new SyncData();
        List<TechnologySyn> technologySyns = new ArrayList<>();
        //1.生成数据
        List<Technology> technologies = technologyService.findAllTechnology();
        for (Technology technology : technologies) {
            TechnologySyn technologySyn = new TechnologySyn();
            BeanUtils.copyProperties(technology, technologySyn);
            List<Rule> rules = ruleDao.findAllByTechnologyId(technology.getId());
            technologySyn.setRules(rules);
            technologySyns.add(technologySyn);
        }
        syncData.setTechnologies(technologySyns);
        String s = JSON.toJSONString(syncData);
        String path = System.getProperty("user.dir") + File.separator + "inspect" + File.separator + "inspect.txt";
        //2.生成json文件
        FileUtil.write(s, path);
        return path;
    }

    @Override
    public void importRules(MultipartFile file) {
        if (file.isEmpty()) {
            return;
        }
        String fileName = file.getOriginalFilename();
        String fileType = fileName.substring(0, fileName.lastIndexOf("."));
        File dest = new File(System.getProperty("user.dir") + File.separator + "inspect" + File.separator + UUIDUtil.getUUID() + File.separator + fileType);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try {
            file.transferTo(dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //1.导入json文件
        String s = readTxt(dest.getAbsolutePath());
        System.out.println(s);
        if (!StringUtils.isEmpty(s)) {

            //2.清洗规则数据
            //3.将数据添加到数据库中
            SyncData syncData = JSON.parseObject(s, SyncData.class);
            List<TechnologySyn> technologies = syncData.getTechnologies();
            if (technologies != null && technologies.size() > 0) {
                for (TechnologySyn technology : technologies) {
                    List<Rule> rules = technology.getRules();
                    if (rules != null && rules.size() > 0) {
                        for (Rule rule : rules) {
                            addRulePlus(rule);
                        }
                    }
                }
            }
        }

    }

    public String readTxt(String filePath) {
        try {
            String encoding = "UTF-8";
            File file = new File(filePath);
            if (file.isFile() && file.exists()) { // 判断文件是否存在
                InputStreamReader read = new InputStreamReader(
                        new FileInputStream(file), encoding);// 考虑到编码格式
                BufferedReader bufferedReader = new BufferedReader(read);
                String lineTxt = null;
                StringBuilder sb = new StringBuilder();
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    sb.append(lineTxt);
                }
                String s = sb.toString();
                read.close();

                return s;
            } else {
                System.out.println("找不到指定的文件");
            }
        } catch (Exception e) {
            System.out.println("读取文件内容出错");
            e.printStackTrace();
        }
        return null;
    }

    public void syncData() {
        //1.导入json数据
        //2.清空数据库
        //3.导入到标准库
    }

}
