/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package com.unis.rotationPlan.info.modular.rpWarnThreshold.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.time.LocalDateTime;
import java.time.Year;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import com.unis.basic.info.modular.grainPriceCollectCitySum.entity.GrainPriceCollectCitySum;
import com.unis.policy.info.modular.alPolicyFileReport.entity.AlPolicyFileReport;
import com.unis.purchaseAndSalesSupervision.modular.pssstorageemptyperiod.entity.PssStorageEmptyPeriod;
import com.unis.purchaseAndSalesSupervision.modular.pssstorageemptyperiod.service.PssStorageEmptyPeriodService;
import com.unis.rotationPlan.info.modular.rpIssuance.entity.RpIssuance;
import com.unis.rotationPlan.info.modular.rpIssuance.service.RpIssuanceService;
import com.unis.rotationPlan.info.modular.rpWarnBiweeklyReport.mapper.RpWarnBiweeklyReportMapper;
import com.unis.rotationPlan.info.modular.rpWarnThresholdconfig.entity.RpWarnThresholdconfig;
import com.unis.rotationPlan.info.modular.rpWarnThresholdconfig.service.RpWarnThresholdconfigService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.Now;
import org.joda.time.DateTimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.unis.common.enums.CommonSortOrderEnum;
import com.unis.common.exception.CommonException;
import com.unis.common.page.CommonPageRequest;
import com.unis.rotationPlan.info.modular.rpWarnThreshold.entity.RpWarnThreshold;
import com.unis.rotationPlan.info.modular.rpWarnThreshold.mapper.RpWarnThresholdMapper;
import com.unis.rotationPlan.info.modular.rpWarnThreshold.param.RpWarnThresholdAddParam;
import com.unis.rotationPlan.info.modular.rpWarnThreshold.param.RpWarnThresholdEditParam;
import com.unis.rotationPlan.info.modular.rpWarnThreshold.param.RpWarnThresholdIdParam;
import com.unis.rotationPlan.info.modular.rpWarnThreshold.param.RpWarnThresholdPageParam;
import com.unis.rotationPlan.info.modular.rpWarnThreshold.service.RpWarnThresholdService;
import sun.rmi.runtime.Log;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 轮换计划-轮换数量预警Service接口实现类
 *
 * @author TS
 * @date  2024/05/08 09:26
 **/
@Service
public class RpWarnThresholdServiceImpl extends ServiceImpl<RpWarnThresholdMapper, RpWarnThreshold> implements RpWarnThresholdService {


    @Resource
    private PssStorageEmptyPeriodService pssStorageEmptyPeriodService;
    @Autowired
    private RpIssuanceService rpIssuanceService;
    @Resource
    private RpWarnBiweeklyReportMapper rpWarnBiweeklyReportMapper;
    @Resource
    private RpWarnThresholdMapper rpWarnThresholdMapper;
    @Autowired
    private RpWarnThresholdconfigService rpWarnThresholdconfigService;

    @Override
    public Page<RpWarnThreshold> page(RpWarnThresholdPageParam rpWarnThresholdPageParam) {
        QueryWrapper<RpWarnThreshold> queryWrapper = new QueryWrapper<>();
        if(ObjectUtil.isAllNotEmpty(rpWarnThresholdPageParam.getSortField(), rpWarnThresholdPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(rpWarnThresholdPageParam.getSortOrder());
            queryWrapper.orderBy(true, rpWarnThresholdPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(rpWarnThresholdPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(RpWarnThreshold::getId);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(RpWarnThresholdAddParam rpWarnThresholdAddParam) {
        RpWarnThreshold rpWarnThreshold = BeanUtil.toBean(rpWarnThresholdAddParam, RpWarnThreshold.class);
        this.save(rpWarnThreshold);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(RpWarnThresholdEditParam rpWarnThresholdEditParam) {
        RpWarnThreshold rpWarnThreshold = this.queryEntity(rpWarnThresholdEditParam.getId());
        BeanUtil.copyProperties(rpWarnThresholdEditParam, rpWarnThreshold);
        this.updateById(rpWarnThreshold);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<RpWarnThresholdIdParam> rpWarnThresholdIdParamList) {
        // 执行删除
        this.removeByIds(CollStreamUtil.toList(rpWarnThresholdIdParamList, RpWarnThresholdIdParam::getId));
    }

    @Override
    public RpWarnThreshold detail(RpWarnThresholdIdParam rpWarnThresholdIdParam) {
        return this.queryEntity(rpWarnThresholdIdParam.getId());
    }

    @Override
    public RpWarnThreshold queryEntity(String id) {
        RpWarnThreshold rpWarnThreshold = this.getById(id);
        if(ObjectUtil.isEmpty(rpWarnThreshold)) {
            throw new CommonException("轮换计划-轮换数量预警不存在，id值为：{}", id);
        }
        return rpWarnThreshold;
    }

    /**
     * ○    轮换数量预警
     * *     ■ 频率：一天一次。
     * *     ■ 功能：超过预警阈值，添加预警记录。
     * *     ● 示例：如果第一个计划是50%，实际生成了40%，生成一条预警数据。
     */
    @Override
    public void taskAction() {
        //查询当前预警配置，并取第一条数据
        List<RpWarnThresholdconfig> rpWarnThresholdconfigs = rpWarnThresholdconfigService.list();
        if (rpWarnThresholdconfigs.isEmpty()){
            log.error("未有预警配置");
            return;
        }
        RpWarnThresholdconfig thresholdconfig = rpWarnThresholdconfigs.get(0); //取第一条数据
        //查询是否有满足条件的已下发的轮换计划
        List<Map<String,Object>> list = rpWarnThresholdMapper.getReportsInfo();
        if (list.isEmpty()){
            log.error("当前时间未有已下发的轮换计划");
            return;
        }
        for (int j = 0; j < list.size(); j++) {
            Map<String,Object> map1 = list.get(j);
            String id = map1.getOrDefault("id","").toString(); //轮换 计划下发id
            String orgId = map1.getOrDefault("orgId","").toString(); //库区id
           // String unitInfoId = map1.getOrDefault("unitInfoId","").toString(); //企业id
            BigDecimal monthWarning = thresholdconfig.getFirstMonthWarning(); //得到第一个月预警值
            //查询轮换计划对应的
            List<Map<String,Object>> list1 = rpWarnThresholdMapper.getReportsInfoByIssuanceId(id);
            BigDecimal jhckslSum = NumberUtil.toBigDecimal("0.0"); //计划出库数量之和
            String fristCarDate = null;
            List<String> hwids = new ArrayList<>();//对应的货位的数据
            //得到第一车入库时间
            for (int i = 0; i < list1.size(); i++) {
                Map<String,Object> map = list1.get(i);
              //  String rpReportId = map.getOrDefault("rpReportId","").toString(); //轮换 计划id
            //    String outId = map.getOrDefault("outId","").toString(); //轮换出库id
                String hwid = map.getOrDefault("hwid","").toString(); //货位id
                String lspzId = map.getOrDefault("lspzId","").toString(); //品种id
                String lsxpzId = map.getOrDefault("lsxpzId","").toString(); //性质id
                BigDecimal jhcksl = NumberUtil.toBigDecimal(map.getOrDefault("jhcksl","").toString()); //计划出库数量
                jhckslSum = NumberUtil.add(jhcksl); //求和
                //查询库级封仓表对应货位的，最近一条封仓数据
                Map<String,Object> fcrqMap = rpWarnThresholdMapper.getSealingRecord(hwid,lspzId,lsxpzId);
                if (ObjectUtil.isEmpty(fcrqMap)){
                    log.error("当前货位未有封仓信息,货位id:"+hwid);
                    continue;
                }
                String fcrq = fcrqMap.getOrDefault("ywrq","").toString(); //封仓日期
                //取得封仓后，第一条出库数据的时间，直接取fcbgz表数据
                //TODO  TS目前未明确轮换计划与出入库之间的数据关联，因此直接使用货位，品种，性质进行查询，待表关系明确之后，再进行处理
                Map<String,Object> fristCarMap = rpWarnThresholdMapper.getFristCarDate(hwid,lspzId,lsxpzId,fcrq);
                //TODO TS 未有出库记录，是否需要进行预警，目前设置未出库不进行预警,
                if (ObjectUtil.isEmpty(fcrqMap)){
                    log.error("当前货位未有出库信息,货位id:"+hwid);
                    continue;
                }
                if (StringUtils.isNotBlank(fristCarDate)){
                   String fristCarDate_ = fristCarMap.getOrDefault("fristCarDate","").toString(); //封仓后第一条出库记录时间
                    //与上一个货位比较时间，取时间最小的
                    if (DateUtil.compare(DateUtil.parseDate(fristCarDate_),DateUtil.parseDate(fristCarDate)) < 0){
                        fristCarDate = fristCarDate_;
                    }
                }else{
                    fristCarDate = fristCarMap.getOrDefault("fristCarDate","").toString(); //封仓后第一条出库记录时间
                }
                //添加货物id
                hwids.add(hwid);
            }
            if (StringUtils.isNotBlank(fristCarDate)){
                log.error("当前轮换计划未有出库记录,轮换id:"+id);
                continue;
            }

            //与当前时间比较，得到相差几月
            Date fristCarDateTime = DateUtil.parseDateTime(fristCarDate);

            Long monthBetween = DateUtil.betweenMonth(fristCarDateTime, new Date(), true);
            if(monthBetween == 0){
                log.error("当前库区未在架空期:"+orgId);
                continue;
            }else if(monthBetween == 1){ //相差一月
                monthWarning = thresholdconfig.getFirstMonthWarning();
            }else if(monthBetween == 2){ //相差二月
                monthWarning = thresholdconfig.getSecondMonthWarning();
            }else if(monthBetween == 3){ //相差三有
                monthWarning = thresholdconfig.getThirdMonthWarning();
            }else if(monthBetween == 4){ //相差四月
                monthWarning = thresholdconfig.getFourthMonthWarning();
            }else{
                log.error("当前库区出库超过四个月，不进行预警,轮换计划id:"+id);
                continue;
            }
            //得到出库相关数据，
            Map<String,Object> cksl = rpWarnThresholdMapper.getCkslSum(orgId,StrUtil.join(", ", hwids),fristCarDate);
            BigDecimal sjckslSum = NumberUtil.toBigDecimal(cksl.getOrDefault("cksl","0.0").toString());
            //得到出库比例
            BigDecimal rotationQuantityPercentage = NumberUtil.mul(NumberUtil.div(sjckslSum,jhckslSum),NumberUtil.toBigDecimal("100")); //得到百分比
            //与架空期对应的月份比较大小
            if (rotationQuantityPercentage.compareTo(monthWarning) < 0){
                //生成预警信息
                RpWarnThreshold rpWarnThreshold = new RpWarnThreshold();
                rpWarnThreshold.setOrgId(Integer.parseInt(orgId));
                rpWarnThreshold.setRpIssuanceId(id);
                rpWarnThreshold.setActualRotationQuantity(NumberUtil.parseInt(cksl.getOrDefault("cksl","0.0").toString()));
                rpWarnThreshold.setRotationQuantityPercentage(rotationQuantityPercentage);
                rpWarnThreshold.setShouldRotationQuantityPercentage(monthWarning);
                rpWarnThreshold.setWarningTime(new Date());
                this.save(rpWarnThreshold);
            }


        }


    }

    /**
     * 获取轮换计划-轮换数量预警自定义分页
     *
     * @param pageParam
     * @return
     */
    @Override
    public IPage<Map<String, Object>> findPage(RpWarnThresholdPageParam pageParam) {
        //条形查询器
        QueryWrapper<RpWarnThreshold> queryWrapper = new QueryWrapper<>();
        //分页相关
        if(StringUtils.isNotBlank(pageParam.getUnitName())){
            queryWrapper.like("e.dwmc",pageParam.getUnitName() );
        }
        Page<RpWarnThreshold> p =new Page<>(pageParam.getCurrent(),pageParam.getSize());
        IPage<Map<String,Object>> page = rpWarnThresholdMapper.selectMyMapsPage(p,queryWrapper);
        return page;
    }
    @Transactional
    @Override
    public void SITRAction() {
        //查询是否有满足条件的已下发的轮换计划(入库)
        List<Map<String,Object>> list = rpWarnThresholdMapper.getReportsInInfo();
        for (int j = 0; j < list.size(); j++) {
            Map<String,Object> map1 = list.get(j);
            String id = map1.getOrDefault("id","").toString(); //轮换 计划下发id
            String rpReportId = map1.getOrDefault("rpReportId","").toString(); //轮换 计划下发id
            String orgId = map1.getOrDefault("orgId","").toString(); //轮换 计划下发id
            String jhwh = map1.getOrDefault("jhwh","").toString(); //轮换 计划文号
            String lhnd = map1.getOrDefault("lhnd","").toString();
            Year year = convertStringToYear(lhnd);
            QueryWrapper<PssStorageEmptyPeriod> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("rp_report_id",rpReportId);
            List<PssStorageEmptyPeriod> pssStorageEmptyPeriodLiat =pssStorageEmptyPeriodService.list(queryWrapper);
            if(pssStorageEmptyPeriodLiat!=null){
                pssStorageEmptyPeriodService.removeByIds(pssStorageEmptyPeriodLiat);
            }
            //根据计划查出库
            List<Map<String,Object>> list1 =rpWarnThresholdMapper.getCk(rpReportId);


            //查询轮换计划对应的入库
          //  List<Map<String,Object>> list1 = rpWarnThresholdMapper.getReportsInInfoByIssuanceId(id);
            BigDecimal jhrkslSum = NumberUtil.toBigDecimal("0.0"); //计划入库数量之和
            for (int i = 0; i < list1.size(); i++) {


                Map<String, Object> map = list1.get(i);

                LocalDateTime dateTime = (LocalDateTime)map.getOrDefault("djsj", LocalDateTime.now()); //第一车出库时间
               String UnitID = (String)map.getOrDefault("UnitID",""); //库区id
               String sjckch = (String)map.getOrDefault("sjckch",""); //仓房id
               String sjhwh = (String)map.getOrDefault("sjhwh",""); //货位id

                // 定义日期时间格式，这应该和数据库中日期时间的格式匹配
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            // 将字符串转换为LocalDateTime
               // LocalDateTime dateTime = LocalDateTime.parse(djsj, formatter);
                // 计算下个月的第一天
                LocalDateTime firstDayOfNextMonth = dateTime.plusMonths(1).withDayOfMonth(1);
                LocalDateTime futureDate = firstDayOfNextMonth.plusMonths(4);
                Map<String, BigDecimal> lhjscount =rpWarnThresholdMapper.selectLHJH(UnitID,rpReportId);
                Map<String, Double> kljz =rpWarnThresholdMapper.selectKLJZ(UnitID, futureDate,rpReportId);
                BigDecimal jhrksl=new BigDecimal(0.00);
                BigDecimal klhjz=new BigDecimal(0.00);
                if(lhjscount!=null){
                    jhrksl=new BigDecimal(lhjscount.get("jhrksl").toString());

                }
                if(kljz!=null){
                    klhjz=new BigDecimal(kljz.get("klhjz").toString());
                }

               Integer rotationStatus;
                if(klhjz==jhrksl){
                    rotationStatus=1;
                }else{
                    rotationStatus=2;
                }

                Map<String,Object> map2 =rpWarnThresholdMapper.getMaxDate(rpReportId,sjhwh);
                LocalDateTime dateTime1 = (LocalDateTime)map2.getOrDefault("djsj", LocalDateTime.now()); //第一车出库时间
                PssStorageEmptyPeriod pssStorageEmptyPeriod =new PssStorageEmptyPeriod();
                pssStorageEmptyPeriod.setCreateTime(new Date());
                pssStorageEmptyPeriod.setUpdateTime(new Date());
                pssStorageEmptyPeriod.setPlanNumber(jhwh);
                pssStorageEmptyPeriod.setPlanYear(year);
                pssStorageEmptyPeriod.setRpReportId(Integer.parseInt(rpReportId));
                pssStorageEmptyPeriod.setOrgId(Integer.parseInt(UnitID));
                pssStorageEmptyPeriod.setBasicStorehouseId(Integer.parseInt(sjckch));
                pssStorageEmptyPeriod.setWarehouseId(Integer.parseInt(sjhwh));
                pssStorageEmptyPeriod.setRotationStatus(rotationStatus);
                Date date = Date.from(futureDate.atZone(ZoneId.systemDefault()).toInstant());
                Date Startdate = Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());

                pssStorageEmptyPeriod.setRotationStart(Startdate);
                pssStorageEmptyPeriod.setRotationEnd(date);
                pssStorageEmptyPeriod.setPlannedQuantity(jhrksl);
                pssStorageEmptyPeriod.setRemainingQuantity(jhrksl.subtract(klhjz));
                pssStorageEmptyPeriod.setDate(Date.from(dateTime1.atZone(ZoneId.systemDefault()).toInstant()));
                pssStorageEmptyPeriodService.save(pssStorageEmptyPeriod);

            }
        }
    }

    private Year convertStringToYear(String lhnd) {
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate localDate = LocalDate.parse(lhnd, formatter);
            return Year.of(localDate.getYear());
        } catch (DateTimeParseException e) {
            System.err.println("解析年份时发生错误：" + e.getMessage());
        }
        return null; // 如果转换失败，则返回null
    }

}
