package com.jjt.emp.service.impl;

import com.jjt.calc.domain.TwinCalcDay;
import com.jjt.calc.domain.TwinCalcHourSpec;
import com.jjt.calc.service.ITwinCalcDayService;
import com.jjt.calc.service.ITwinCalcHourSpecService;
import com.jjt.common.utils.DateUtils;
import com.jjt.common.utils.StringUtils;
import com.jjt.emp.domain.TwinEmp;
import com.jjt.emp.domain.TwinEmpCalc;
import com.jjt.emp.domain.TwinEmpConfig;
import com.jjt.emp.domain.TwinEmpDetail;
import com.jjt.emp.mapper.TwinEmpCalcMapper;
import com.jjt.emp.service.ITwinEmpCalcService;
import com.jjt.emp.service.ITwinEmpConfigService;
import com.jjt.emp.service.ITwinEmpService;
import com.jjt.utils.Tools;
import com.jjt.wkEmp.domain.TwinWkEmpRota;
import com.jjt.wkEmp.service.ITwinWkEmpRotaService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 员工产量统计Service业务层处理
 *
 * @author wukai
 * @date 2025-01-18
 */
@Service
public class TwinEmpCalcServiceImpl implements ITwinEmpCalcService {
    @Resource
    private TwinEmpCalcMapper twinEmpCalcMapper;
    @Resource
    private ITwinCalcHourSpecService hourSpecService;
    @Resource
    private ITwinEmpService empService;
    @Resource
    private ITwinEmpConfigService empConfigService;
    @Resource
    private ITwinCalcDayService twinCalcDayService;
    @Resource
    private SqlSessionFactory factory;
    @Resource
    private ITwinWkEmpRotaService rotaService;

    /**
     * 查询员工产量统计
     *
     * @param calcId 员工产量统计主键
     * @return 员工产量统计
     */
    @Override
    public TwinEmpCalc selectTwinEmpCalcByCalcId(Long calcId) {
        return twinEmpCalcMapper.selectTwinEmpCalcByCalcId(calcId);
    }

    /**
     * 查询员工产量统计列表
     *
     * @param twinEmpCalc 员工产量统计
     * @return 员工产量统计
     */
    @Override
    public List<TwinEmpCalc> selectTwinEmpCalcList(TwinEmpCalc twinEmpCalc) {
        return twinEmpCalcMapper.selectTwinEmpCalcList(twinEmpCalc);
    }

    /**
     * 新增员工产量统计
     *
     * @param twinEmpCalc 员工产量统计
     * @return 结果
     */
    @Override
    public int insertTwinEmpCalc(TwinEmpCalc twinEmpCalc) {
        return twinEmpCalcMapper.insertTwinEmpCalc(twinEmpCalc);
    }

    /**
     * 修改员工产量统计
     *
     * @param twinEmpCalc 员工产量统计
     * @return 结果
     */
    @Override
    public int updateTwinEmpCalc(TwinEmpCalc twinEmpCalc) {
        return twinEmpCalcMapper.updateTwinEmpCalc(twinEmpCalc);
    }

    /**
     * 批量删除员工产量统计
     *
     * @param calcIds 需要删除的员工产量统计主键
     * @return 结果
     */
    @Override
    public int deleteTwinEmpCalcByCalcIds(Long[] calcIds) {
        return twinEmpCalcMapper.deleteTwinEmpCalcByCalcIds(calcIds);
    }

    /**
     * 删除员工产量统计信息
     *
     * @param calcId 员工产量统计主键
     * @return 结果
     */
    @Override
    public int deleteTwinEmpCalcByCalcId(Long calcId) {
        return twinEmpCalcMapper.deleteTwinEmpCalcByCalcId(calcId);
    }

    /**
     * 按日统计
     *
     * @param date 日期
     * @return 结果
     */
    @Override
    public int calc(Date date) {
        //先删除
        twinEmpCalcMapper.deleteTwinEmpCalcByDate(date);

        //获取统计数据
        List<TwinCalcHourSpec> specHourList = hourSpecService.selectTwinCalcHourSpecListByDate(date);
        specHourList.forEach(TwinCalcHourSpec::setTeam);
        // 按照deviceId、density、mick、team，并统计每组的length总和
        Map<String, List<TwinCalcHourSpec>> specHourMap = specHourList.stream().collect(Collectors.groupingBy(o -> o.getDeviceId() + "-" + o.getTeam(), LinkedHashMap::new, Collectors.toList()));
        List<TwinCalcDay> twinCalcDays = twinCalcDayService.selectTwinCalcDayListByTime(date, date);
        Map<Long, TwinCalcDay> calcMap = twinCalcDays.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, o -> o));
        TwinEmp emp = empService.selectTwinEmpByDate(date);

        List<TwinEmpConfig> configs = empConfigService.selectTwinEmpConfigList(new TwinEmpConfig());
        Map<BigDecimal, BigDecimal> configMap = configs.stream().collect(Collectors.toMap(o -> o.getDensity().setScale(2, RoundingMode.HALF_UP), TwinEmpConfig::getPrice));

        List<TwinEmpCalc> calcList = new ArrayList<>();
        process(true, emp, calcMap, configMap, calcList, specHourMap);
        process(false, emp, calcMap, configMap, calcList, specHourMap);
        if (calcList.size() > 0) {
            try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
                TwinEmpCalcMapper mapper = sqlSession.getMapper(TwinEmpCalcMapper.class);
                calcList.forEach(mapper::insertTwinEmpCalc);
                sqlSession.commit();
            }
        }
        return 1;
    }


    /**
     * @param flag true为A班false为B班
     */
    private void process(boolean flag, TwinEmp emp, Map<Long, TwinCalcDay> calcMap, Map<BigDecimal, BigDecimal> configMap, List<TwinEmpCalc> calcList, Map<String, List<TwinCalcHourSpec>> specHourMap) {
        List<TwinEmpDetail> list = emp.getTwinEmpDetailListA();
        String team = "A";
        if (!flag) {
            team = "B";
            list = emp.getTwinEmpDetailListB();
        }
        for (TwinEmpDetail d : list) {
            Long[] devices = getDevices(d.getDevices());
            for (int i = 0; i < devices.length; i++) {
                Long deviceId = devices[i];
                List<TwinCalcHourSpec> specs = specHourMap.get(deviceId + "-" + team);
                if (specs == null || specs.size() == 0) {
                    continue;
                }
                //按密度和米克重、毛高分组统计
                Map<String, BigDecimal> resultMap = specs.stream().collect(Collectors.groupingBy(t -> t.getDensity() + "-" + t.getMick() + "-" + t.getHeight(), Collectors.reducing(BigDecimal.ZERO, TwinCalcHourSpec::getLength, BigDecimal::add)));
                for (String ss : resultMap.keySet()) {
                    String[] temp = ss.split("-");
                    BigDecimal density = new BigDecimal(temp[0]).setScale(2, RoundingMode.HALF_UP);
                    Integer mick = Integer.parseInt(temp[1]);
                    TwinCalcDay td = calcMap.get(deviceId);
                    TwinEmpCalc calc = new TwinEmpCalc();
                    calc.setDeviceId(deviceId);
                    if (StringUtils.isNotEmpty(temp[2]) && !"null".equals(temp[2])) {
                        BigDecimal height = new BigDecimal(temp[2]).setScale(2, RoundingMode.HALF_UP);
                        calc.setHeight(height);
                    }
                    calc.setEfficiency(td.getEfficiencyA());
                    calc.setEmpDate(td.getTime());
                    BigDecimal length = resultMap.get(ss);
                    if (!flag) {
                        calc.setEfficiency(td.getEfficiencyB());
                    }
                    if (length.compareTo(BigDecimal.ZERO) == 0) {
                        continue;
                    }
                    calc.setLength(length);
                    calc.setEmpTeam(d.getEmpTeam());
                    calc.setEmpName(d.getEmpName());
                    calc.setMick(mick);
                    calc.setDensity(density);
                    BigDecimal price = configMap.get(Tools.density(density));
                    calc.setPrice(price);
                    if (price != null) {
                        BigDecimal total = length.multiply(price);
                        calc.setTotalPrice(total);
                    }
                    calcList.add(calc);
                }
            }
        }
    }

    private Long[] getDevices(String d) {
        String[] temp = d.split(",");
        Set<Long> set = new HashSet<>();
        for (String s : temp) {
            String[] ss = s.split("-");
            if (ss.length > 1) {
                Long st = Long.parseLong(ss[0]);
                Long ed = Long.parseLong(ss[1]);
                for (long i = st; i <= ed; i++) {
                    set.add(i);
                }
            } else {
                set.add(Long.parseLong(s));
            }
        }
        Long[] devices = new Long[set.size()];
        set.toArray(devices);
        return devices;
    }


    /**
     * 按日查询
     *
     * @param date 日期
     * @return 结果
     */
    @Override
    public List<TwinEmpCalc> selectTwinEmpCalcListByDate(Date date) {
        TwinEmpCalc search = new TwinEmpCalc();
        search.setEmpDate(date);
        return selectTwinEmpCalcList(search);
    }

    /**
     * 按月查询
     *
     * @param month 月份
     * @return 结果
     */
    @Override
    public List<TwinEmpCalc> selectTwinEmpCalcListByMonth(String month) {
        return twinEmpCalcMapper.selectTwinEmpCalcListByMonth(month);
    }

    /**
     * 按日统计,从MES同步过来的
     *
     * @param date 日期
     * @return 结果
     */
    @Override
    public void calcNew(Date date) {
        //先删除
        twinEmpCalcMapper.deleteTwinEmpCalcByDate(date);
        // 获取稼动率
        List<TwinCalcDay> twinCalcDays = twinCalcDayService.selectTwinCalcDayListByTime(date, date);
        Map<Long, TwinCalcDay> calcMap = twinCalcDays.stream().collect(Collectors.toMap(TwinCalcDay::getDeviceId, o -> o));

        //获取价格配置
        List<TwinEmpConfig> configs = empConfigService.selectTwinEmpConfigList(new TwinEmpConfig());
        Map<BigDecimal, BigDecimal> configMap = configs.stream().collect(Collectors.toMap(o -> o.getDensity().setScale(2, RoundingMode.HALF_UP), TwinEmpConfig::getPrice));

        //获取统计数据
        List<TwinCalcHourSpec> specHourList = hourSpecService.selectTwinCalcHourSpecListByDate(date);
        //设置分组
        specHourList.forEach(TwinCalcHourSpec::setTeam);
        // 按照deviceId分组
        Map<Long, List<TwinCalcHourSpec>> specHourMap = specHourList.stream().collect(Collectors.groupingBy(TwinCalcHourSpec::getDeviceId, LinkedHashMap::new, Collectors.toList()));
        //按设备。。。小时。。。（员工号/姓名) 存储
        Map<Long, Map<Integer, String>> empMap = new HashMap<>(16);
        List<TwinWkEmpRota> rotas = rotaService.selectTwinWkEmpRotaListByDate(date);
        for (TwinWkEmpRota rota : rotas) {
            String[] devices = rota.getDevices().split(",");
            LocalDateTime st = DateUtils.toLocalDateTime(rota.getInTime());
            LocalDateTime et = DateUtils.toLocalDateTime(rota.getOutTime());
            Map<Integer, String> hourMap = new HashMap<>(16);
            while (st.isBefore(et)) {
                int hour = st.getHour();
                String str = rota.getEmpId() + "/" + rota.getEmpName();
                hourMap.put(hour, str);
                st = st.plusHours(1);
            }
            for (String s : devices) {
                Long id = Long.parseLong(s);
                Map<Integer, String> map = empMap.get(id);
                if (map != null) {
                    map.putAll(hourMap);
                } else {
                    empMap.put(id, hourMap);
                }
            }
        }

        List<TwinEmpCalc> calcList = new ArrayList<>();
        for (Long id : specHourMap.keySet()) {
            List<TwinCalcHourSpec> list = specHourMap.get(id);
            Map<Integer, String> map = empMap.get(id);
            if (map == null) {
                continue;
            }
            list.forEach(spec -> {
                String str = map.get(spec.getHour());
                if (StringUtils.isNotEmpty(str)) {
                    String[] tmp = str.split("/");
                    spec.setEmpId(tmp[0]);
                    spec.setEmpName(tmp[1]);
                }
            });

            //按密度和米克重、毛高分组统计
            Map<String, BigDecimal> resultMap = list.stream().collect(Collectors.groupingBy(t -> t.getDensity() + "-" + t.getMick() + "-" + t.getHeight() + "-" + t.getEmpName() + "-" + t.getTeam() + "-", Collectors.reducing(BigDecimal.ZERO, TwinCalcHourSpec::getLength, BigDecimal::add)));
            for (String ss : resultMap.keySet()) {
                String[] temp = ss.split("-");
                BigDecimal density = new BigDecimal(temp[0]).setScale(2, RoundingMode.HALF_UP);
                Integer mick = Integer.parseInt(temp[1]);
                TwinCalcDay td = calcMap.get(id);
                TwinEmpCalc calc = new TwinEmpCalc();
                calc.setDeviceId(id);
                if (StringUtils.isNotEmpty(temp[2]) && !"null".equals(temp[2])) {
                    BigDecimal height = new BigDecimal(temp[2]).setScale(2, RoundingMode.HALF_UP);
                    calc.setHeight(height);
                }
                String name = temp[3];
                String team = temp[4];
                calc.setEmpDate(td.getTime());
                if ("A".equals(team)) {
                    calc.setEfficiency(td.getEfficiencyA());
                } else {
                    calc.setEfficiency(td.getEfficiencyB());
                }
                BigDecimal length = resultMap.get(ss);
                if (length.compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }
                calc.setLength(length);
                calc.setEmpTeam(team);
                calc.setEmpName(name);
                calc.setMick(mick);
                calc.setDensity(density);
                BigDecimal price = configMap.get(Tools.density(density));
                calc.setPrice(price);
                if (price != null) {
                    BigDecimal total = length.multiply(price);
                    calc.setTotalPrice(total);
                }
                calcList.add(calc);
            }
        }

        if (calcList.size() > 0) {
            try (SqlSession sqlSession = factory.openSession(ExecutorType.BATCH, false)) {
                TwinEmpCalcMapper mapper = sqlSession.getMapper(TwinEmpCalcMapper.class);
                calcList.forEach(mapper::insertTwinEmpCalc);
                sqlSession.commit();
            }
        }
    }
}
