package cn.wise.sc.cement.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.wise.sc.cement.business.entity.*;
import cn.wise.sc.cement.business.mapper.*;
import cn.wise.sc.cement.business.model.BaseResponse;
import cn.wise.sc.cement.business.model.LoginUser;
import cn.wise.sc.cement.business.model.PageQuery;
import cn.wise.sc.cement.business.model.query.*;
import cn.wise.sc.cement.business.model.vo.StandardValueVo;
import cn.wise.sc.cement.business.model.vo.StandardVo;
import cn.wise.sc.cement.business.service.ISampleCheckService;
import cn.wise.sc.cement.business.service.IStandardService;
import cn.wise.sc.cement.business.service.IStandardValueService;
import cn.wise.sc.cement.business.service.ISysUserService;
import cn.wise.sc.cement.business.util.ExcelUtil;
import cn.wise.sc.cement.business.util.ObjUtils;
import cn.wise.sc.cement.business.util.weixin.Global;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ztw
 * @since 2020-09-04
 */
@Service
public class StandardServiceImpl extends ServiceImpl<StandardMapper, Standard> implements IStandardService {

    @Resource
    private StandardMapper standardMapper;
    @Autowired
    private ISysUserService userService;
    @Resource
    private StandardEnterMapper standardEnterMapper;
    @Resource
    private StandardOutMapper standardOutMapper;
    @Autowired
    private IStandardValueService standardValueService;
    @Autowired
    private CommonServiceImpl commonService;
    @Autowired
    private ISampleCheckService iSampleCheckService;
    @Resource
    private SysApprovalMapper sysApprovalMapper;
    @Autowired
    private WeiXinService weiXinService;
    @Value("${weixin.systemUrl}")
    private String systemUrl;


    /**
     * 分页查询
     *
     * @param pageQuery
     * @param name
     * @param supplierName
     * @return
     */
    @Override
    public BaseResponse<IPage<Standard>> getPage(PageQuery pageQuery, String name, String supplierName) {
        QueryWrapper<Standard> qw = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(name)) {
            qw.like("name", name);
        }
        if (StringUtils.isNotEmpty(supplierName)) {
            qw.like("supplier_name", supplierName);
        }
        qw.orderByDesc("name");
        IPage<Standard> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        page = standardMapper.selectPage(page, qw);
        return BaseResponse.okData(page);
    }

    /**
     * 标样信息列表导出
     *
     * @param name
     * @param supplierName
     * @param fileName
     * @param response
     */
    @Override
    public void export(String name, String supplierName, String fileName, HttpServletResponse response) {
        Map<String, Object> params = new HashMap<>();
        params.put("supplierName", supplierName);
        params.put("name", name);
        List<Map<String, Object>> list = standardMapper.exportList(params);

        if (!CollectionUtils.isEmpty(list)) {
            Map<String, Object> map = list.get(0);
            String[] headers = new String[map.size()];
            headers[0] = "序号";
            headers[1] = "标样名称";
            headers[2] = "标物代号";
            headers[3] = "经销单位";
            headers[4] = "存放位置";
            headers[5] = "进样日期";
            headers[6] = "有效日期";
            headers[7] = "剩余库存";
            headers[8] = "状态";

            List<Object[]> datas = new ArrayList<>(list.size());
            for (Map<String, Object> m : list) {
                Object[] objects = new Object[headers.length];
                for (int j = 0; j < headers.length; j++) {
                    String obj = m.get(headers[j]).toString();
                    if (j == 0) {
                        obj = obj.split("\\.")[0];
                    }
                    objects[j] = obj;
                }
                datas.add(objects);
            }
            ExcelUtil.excelExport(
                    fileName == null || fileName.trim().length() <= 0 ? "标样信息" : fileName, headers,
                    datas, response);
        }
    }

    /**
     * 新增标样
     *
     * @param query
     * @return
     */
    @Transactional
    @Override
    public BaseResponse<Standard> create(StandardQuery query) {
        if (StringUtils.isEmpty(query.getName())) {
            return BaseResponse.errorMsg("标样名称不能为空!");
        }
        LoginUser loginUser = userService.getLoginUser();
        if (loginUser == null) {
            return BaseResponse.errorMsg("请登录账号");
        }

        QueryWrapper<Standard> qw = new QueryWrapper<>();
        qw.eq("name", query.getName());
        int count = standardMapper.selectCount(qw);
        if (count > 0) {
            return BaseResponse.errorMsg(query.getName() + "已存在");
        }
        Standard standard = new Standard();
        BeanUtils.copyProperties(query, standard);
        if(query.getEnterNum() != null && query.getUnitStock() != null){
            BigDecimal stockNum = new BigDecimal(query.getEnterNum()).multiply(query.getUnitStock());
            standard.setStockNum(stockNum);
        }else{
            standard.setStockNum(new BigDecimal(0));
        }
        standard.setStatus(1)
                .setCreateTime(LocalDateTime.now());
        standardMapper.insert(standard);
        //添加标准值
        if (query.getStandardValueQueryList() != null && query.getStandardValueQueryList().size() > 0) {
            List<StandardValueQuery> standardValueQueryList = query.getStandardValueQueryList();

            List<StandardValue> standardValueList = new ArrayList<>();
            for (StandardValueQuery standardValueQuery : standardValueQueryList) {
                StandardValue standardValue = new StandardValue();
                standardValue.setStandardId(standard.getId())
                        .setElementName(standardValueQuery.getElementName())
                        .setCreateTime(LocalDateTime.now());
                if (standardValueQuery.getElementValue() != null && standardValueQuery.getElementValue().size() > 0) {
                    String elementValue = JSON.toJSON(standardValueQuery.getElementValue()).toString();
                    standardValue.setElementValue(elementValue);
                } else {
                    standardValue.setElementValue(null);
                }
                standardValueList.add(standardValue);
            }
            standardValueService.saveBatch(standardValueList);
        }
        //标样入库记录添加
        StandardEnter enter = new StandardEnter();
        enter.setStandardId(standard.getId())
                .setUserId(loginUser.getId())
                .setEnterNum(query.getEnterNum())  //入库数量  多少瓶
                .setCreateTime(LocalDateTime.now())
                .setRemark("新增标样");
        standardEnterMapper.insert(enter);
        //保存标样材料信息
        Boolean ref = commonService.saveEntityEnclosure(EntityEnclosure.EntityType.STANDARD_SAMPLE, standard.getId(), query.getEnclosureQueryList());
        if (!ref) {
            return BaseResponse.errorMsg("保存保存校核附件失败!");
        }

        return BaseResponse.okData(standard);
    }

    /**
     * 修改标样
     *
     * @param query
     * @return
     */
    @Transactional
    @Override
    public BaseResponse<Standard> update(StandardQuery query) {
        if (StringUtils.isEmpty(query.getName())) {
            return BaseResponse.errorMsg("标样名称不能为空!");
        }
        QueryWrapper<Standard> qw = new QueryWrapper<>();
        qw.eq("name", query.getName());
        qw.ne("id", query.getId());
        int count = standardMapper.selectCount(qw);
        if (count > 0) {
            return BaseResponse.errorMsg(query.getName() + "已存在");
        }
        Standard standard = new Standard();
        BeanUtils.copyProperties(query, standard);
        if(query.getEnterNum() != null && query.getUnitStock() != null){
            BigDecimal stockNum = new BigDecimal(query.getEnterNum()).multiply(query.getUnitStock());
            standard.setStockNum(stockNum);
        }
        standardMapper.updateById(standard);
        //添加标准值
        if (query.getStandardValueQueryList() != null && query.getStandardValueQueryList().size() > 0) {
            //删除之前的标准值信息
            QueryWrapper<StandardValue> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("standard_id", standard.getId());
            standardValueService.remove(queryWrapper);
            //添加新的标准值
            List<StandardValueQuery> standardValueQueryList = query.getStandardValueQueryList();
            List<StandardValue> standardValueList = new ArrayList<>();
            for (StandardValueQuery standardValueQuery : standardValueQueryList) {
                StandardValue standardValue = new StandardValue();
                standardValue.setStandardId(standard.getId())
                        .setElementName(standardValueQuery.getElementName())
                        .setCreateTime(LocalDateTime.now());
                if (standardValueQuery.getElementValue() != null && standardValueQuery.getElementValue().size() > 0) {
                    String elementValue = JSON.toJSON(standardValueQuery.getElementValue()).toString();
                    standardValue.setElementValue(elementValue);
                } else {
                    standardValue.setElementValue(null);
                }
                standardValueList.add(standardValue);
            }
            standardValueService.saveBatch(standardValueList);
        }
        //保存标样材料信息
        Boolean ref = commonService.saveEntityEnclosure(EntityEnclosure.EntityType.STANDARD_SAMPLE, standard.getId(), query.getEnclosureQueryList());
        if (!ref) {
            return BaseResponse.errorMsg("保存保存校核附件失败!");
        }
        return BaseResponse.okData(standard);
    }

    @Resource
    private EntityEnclosureMapper entityEnclosureMapper;

    /**
     * 查看历史标样材料信息
     *
     * @param id
     * @return
     */
    @Override
    public BaseResponse<List<EntityEnclosure>> getHistoryStandard(Integer id) {
        QueryWrapper<EntityEnclosure> wrapper = new QueryWrapper<>();
        wrapper.eq("entity_type", EntityEnclosure.EntityType.STANDARD_SAMPLE);
        wrapper.eq("entity_id", id);
        List<EntityEnclosure> entityEnclosureList = entityEnclosureMapper.selectList(wrapper);
        return BaseResponse.okData(entityEnclosureList);
    }

    /**
     * 标样详情
     *
     * @param id 标样表id
     * @return
     */
    @Override
    public BaseResponse<StandardVo> getDetail(Integer id) {
        Standard standard = standardMapper.selectById(id);
        if (standard == null) {
            return BaseResponse.errorMsg("信息错误!");
        }
        StandardVo standardVo = new StandardVo();
        BeanUtils.copyProperties(standard, standardVo);
        List<EntityEnclosure> entityEnclosureList = commonService.getEnclosureList
                (EntityEnclosure.EntityType.STANDARD_SAMPLE, standard.getId());

        List<EnclosureQuery> enclosureQueryList = new ArrayList<>();
        for (EntityEnclosure entityEnclosure : entityEnclosureList) {
            EnclosureQuery enclosureQuery = new EnclosureQuery();
            enclosureQuery.setAlias(entityEnclosure.getAlias())
                    .setEnclosureUrl(entityEnclosure.getEnclosureUrl())
                    .setExtName(entityEnclosure.getExtName());
            enclosureQueryList.add(enclosureQuery);
        }
        standardVo.setEnclosureQueryList(enclosureQueryList);

        QueryWrapper<StandardValue> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("standard_id", standard.getId());
        List<StandardValue> standardValueList = standardValueService.list(queryWrapper);
        standardVo.setStandardValueList(standardValueList);
        return BaseResponse.okData(standardVo);
    }

    /**
     * 新增入库
     *
     * @param query
     * @return
     */
    @Transactional
    @Override
    public BaseResponse<String> enter(ChangeStockQuery query) {
        if (query == null || query.getId() == null) {
            return BaseResponse.errorMsg("参数错误!");
        }
        Standard standard = standardMapper.selectById(query.getId());
        if (standard == null) {
            return BaseResponse.errorMsg("数据错误!");
        }
        StandardEnter enter = new StandardEnter();
        enter.setStandardId(standard.getId())
                .setUserId(userService.getLoginUser().getId())
                .setEnterNum(query.getEnterNum())
                .setCreateTime(LocalDateTime.now())
                .setRemark(query.getRemark());

        standardEnterMapper.insert(enter);
        standard.setStockNum(standard.getStockNum().add(standard.getUnitStock().multiply(new BigDecimal(query.getEnterNum()))));
        standardMapper.updateById(standard);
        return BaseResponse.okData("新增入库完成");
    }

    /**
     * 领用出库
     *
     * @param query
     * @return
     */
    @Transactional
    @Override
    public BaseResponse<String> out(ChangeStockQuery query) {
        if (query == null || query.getId() == null) {
            return BaseResponse.errorMsg("参数错误!");
        }
        Standard standard = standardMapper.selectById(query.getId());
        if (standard == null) {
            return BaseResponse.errorMsg("数据错误!");
        }
        StandardOut out = new StandardOut();
        out.setStandardId(standard.getId())
                .setUserId(userService.getLoginUser().getId())
                .setCollectNum(query.getOutNum())
                .setCreateTime(LocalDateTime.now())
                .setRemark(query.getRemark());
        standardOutMapper.insert(out);
        standard.setStockNum(standard.getStockNum().subtract(out.getCollectNum()));
        standardMapper.updateById(standard);
        return BaseResponse.okData("领用出库完成");
    }

    /**
     * 判断标样数量是否小于设定的最小值 如果小于等于，进行提醒
     * 判断标样是否快过期 过期前15天进行提醒
     * @return
     */
    @Override
    @Scheduled(cron = "0 0 6 * * *")
    public BaseResponse<String> checkStockNum(){
        //消息推送
        List<Integer> approvalIdList = sysApprovalMapper.getApprovalId("标样管理");
        if (approvalIdList == null) {
            return BaseResponse.errorMsg("标样管理信息错误");
        }
        String userIds = "";
        for(Integer testEQId : approvalIdList ){
            SysUser testEQUser = userService.getById(testEQId);
            if(testEQUser == null){
                return BaseResponse.errorMsg("设备检定信息错误");
            }
            if(StringUtils.isNotBlank(testEQUser.getWxId())){
                userIds = userIds.equals("")?testEQUser.getWxId():userIds+"|"+testEQUser.getWxId();
            }
        }
        QueryWrapper<Standard> qw = new QueryWrapper<>();
        qw.eq("status",1);
        List<Standard> standardList = standardMapper.selectList(qw);
        //当前日期
        LocalDate nowDate = LocalDate.now();
        for(Standard st : standardList){
            if(st.getLeastNum() != null && st.getStockNum() != null){
                if(st.getStockNum().compareTo(st.getLeastNum())<1){
                    //发送企业微信消息内容
                    String content="你好！标样名称："+st.getName()+"，代号："+st.getCode()+"的标样数量小于设定的最小值，新增标样数量后请及时更新系统，如果已新增完毕请前往\n" +
                            systemUrl+"更新标样记录。";
                    System.out.println("**************************content**********************");
                    System.out.println(content);
                    weiXinService.sendTextMessage(userIds, content);
                }
            }
            if(st.getValidDate() != null){
                LocalDate expireDate =  st.getValidDate().minusDays(15);
                if(expireDate.isEqual(nowDate) || expireDate.isBefore(nowDate)){
                    //发送企业微信消息内容
                    String content="你好！标样名称："+st.getName()+"，代号："+st.getCode()+"的标样即将过期，请尽快处理，如果已经处理，请前往\n" +
                            systemUrl+"更新标样记录。";
                    System.out.println("**************************content**********************");
                    System.out.println(content);
                    weiXinService.sendTextMessage(userIds, content);
                }
            }

        }
        return BaseResponse.okMsg("成功");
    }

    /**
     * 变更有效期
     *
     * @param query
     * @return
     */
    @Transactional
    @Override
    public BaseResponse<String> changeValidDate(ChangeValidDateQuery query) {
        if (query == null || query.getId() == null) {
            return BaseResponse.errorMsg("参数错误!");
        }
        Standard standard = standardMapper.selectById(query.getId());
        if (standard == null) {
            return BaseResponse.errorMsg("数据错误!");
        }

        standard.setValidDate(query.getValidDate());
        standardMapper.updateById(standard);
        return BaseResponse.okData("变更有效期完成");
    }

    /**
     * 过期处置
     *
     * @param id
     * @return
     */
    @Transactional
    @Override
    public BaseResponse<String> overdue(Integer id) {
        if (id == null) {
            return BaseResponse.errorMsg("参数错误!");
        }
        Standard standard = standardMapper.selectById(id);
        if (standard == null) {
            return BaseResponse.errorMsg("数据错误!");
        }
        standard.setStatus(0);
        standardMapper.updateById(standard);
        return BaseResponse.okData("过期处置完成");
    }

    @Override
    public BaseResponse<List<StandardValueVo>> getStandardDetailList() {

        List<StandardValueVo> standardValueVos = standardMapper.getStandardDetaulList();
        if (standardValueVos.size() != 0) {
            return BaseResponse.okData(standardValueVos);
        } else {
            return BaseResponse.errorMsg("没找数据!");
        }
    }

    @Override
    public List<GroupStandard> getStandards(String name) {

        //获取标样信息
        List<StandardGroupDto> list = standardMapper.getStandardsByGroup();
        List<GroupStandard> rts = new ArrayList<>(list.size());
        Set<Integer> standardIds = new HashSet<>();
        for (StandardGroupDto tmp : list) {
            //将每个标准值根据GroupId(样品id)分组
            if (!standardIds.contains(tmp.getGroupId())) {
                standardIds.add(tmp.getGroupId());
                //样品标样Vo
                GroupStandard groupStandard = new GroupStandard();
                groupStandard.setGroupName(tmp.getGroupName());
                Map<String, String> map = new HashMap<>();
                List<KeyValueMap> keyValueMaps = ObjUtils.str2Obj(tmp.getElementValue());
                //将标样元素添加进样品标样
                keyValueMaps
                        .stream()
                        .filter(arg -> "标准值".equals(arg.getName()))
                        .findFirst()
                        .ifPresent(arg -> {
                            map.put(tmp.getElementName(), arg.getValue());
                        });
                groupStandard.setMap(map);
                rts.add(groupStandard);
            } else {
                //根据groupName找到标准值
                rts.stream()
                        .filter(arg -> arg.getGroupName().equals(tmp.getGroupName()))
                        .findFirst()
                        .ifPresent(arg -> {
                            List<KeyValueMap> keyValueMaps = ObjUtils.str2Obj(tmp.getElementValue());
                            //将新的标准添加到map
                            keyValueMaps
                                    .stream()
                                    .filter(opt -> "标准值".equals(opt.getName()))
                                    .findFirst()
                                    .ifPresent(opt -> arg.getMap().put(tmp.getElementName(), opt.getValue()));
                        });
            }
        }

        //获取历史样品信息
        List<SampleCheck> sampleChecks = iSampleCheckService.list();
        if (CollectionUtil.isEmpty(sampleChecks)) {
            return rts;
        }
        Set<String> cementCodes = sampleChecks.stream()
                .map(SampleCheck::getCementCode).collect(Collectors.toSet());
        //根据cementCodes和team_group_id计算多个平行样的平均值
        for (String cementCode : cementCodes) {
            List<SampleCheck> collect = sampleChecks
                    .stream()
                    .filter(arg -> arg.getCementCode().equals(cementCode)).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(collect)) {
                continue;
            }
            Set<Integer> groupIds = collect.stream()
                    .map(SampleCheck::getTeamGroupId).collect(Collectors.toSet());
            //根据groupI处理team检测值
            for (Integer groupId : groupIds) {
                List<SampleCheck> checkGroups = collect.stream()
                        .filter(arg -> arg.getTeamGroupId().intValue() == groupId)
                        .collect(Collectors.toList());
                if (CollectionUtil.isEmpty(checkGroups)) {
                    continue;
                }
                //将每个元素组的所有元素的标准值累加
                Map<String, BigDecimal> elementMap = new HashMap<>();
                checkGroups.forEach(arg -> {
                    List<KeyValueMap> keyValueMaps = ObjUtils.str2Obj(arg.getCountResults());
                    //将样品的输入值添加到map中
                    keyValueMaps
                            .forEach(opt -> {
                                if (elementMap.containsKey(opt.getName())) {
                                    elementMap.get(opt.getName()).add(new BigDecimal(StrUtil.isEmpty(opt.getValue()) ? "0" : opt.getValue()));
                                } else {
                                    elementMap.put(opt.getName(), new BigDecimal(StrUtil.isEmpty(opt.getValue()) ? "0" : opt.getValue()));
                                }
                            });
                });
                //求平均
                GroupStandard groupStandard = new GroupStandard();
                Map<String, String> map = new HashMap<>();
                groupStandard.setMap(map);
                groupStandard.setCementCode(cementCode);
                groupStandard.setGroupName(checkGroups.get(0).getTeamGroupName() + "|" + cementCode);
                if (CollectionUtil.isEmpty(elementMap)) {
                    continue;
                }
                elementMap.keySet().forEach(opt -> {
                    BigDecimal avg = elementMap.get(opt)
                            .divide(new BigDecimal(checkGroups.size()))
                            .setScale(2, RoundingMode.HALF_DOWN);
                    map.put(opt, avg.toString());
                });
                rts.add(groupStandard);
            }
        }
        if (!StrUtil.isEmpty(name)) {
            return rts.stream()
                    .filter(opt -> opt.getGroupName().contains(name) || name.equals(opt.getCementCode()))
                    .collect(Collectors.toList());
        }
        return rts;
    }

    public static void main(String[] args) {
        BigDecimal bigDecimal = new BigDecimal(111);
        System.out.println(bigDecimal.toString());
    }

}
