package com.njcn.harmonic.service.send.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrBuilder;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.harmonic.mapper.send.PqTypicalSourceCreatePOMapper;
import com.njcn.harmonic.pojo.dto.PqTypicalSourceCreateDTO;
import com.njcn.harmonic.pojo.param.SendQueryParam;
import com.njcn.harmonic.pojo.param.UploadDataParam;
import com.njcn.harmonic.pojo.param.UploadParam;
import com.njcn.harmonic.pojo.po.send.PqTypicalSourceCreatePO;
import com.njcn.harmonic.pojo.po.upload.RUploadDataLog;
import com.njcn.harmonic.pojo.po.upload.RUploadEvaluationDataD;
import com.njcn.harmonic.service.send.PqTypicalSourceCreatePOService;
import com.njcn.harmonic.service.upload.IRUploadDataLogService;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.po.Dept;
import com.njcn.web.enums.GWSendEnum;
import com.njcn.web.pojo.param.SendParam;
import com.njcn.web.utils.GwSendUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 *
 * Description:
 * Date: 2023/12/12  15:16【需求编号】
 *
 * @author clam
 * @version V1.0.0
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PqTypicalSourceCreatePOServiceImpl extends ServiceImpl<PqTypicalSourceCreatePOMapper, PqTypicalSourceCreatePO> implements PqTypicalSourceCreatePOService {

    private final DeptFeignClient deptFeignClient;

    private final IRUploadDataLogService irUploadDataLogService;

    @Override
    public Page<PqTypicalSourceCreatePO> queryPage(SendQueryParam.SendPageParam param) {
        Page<PqTypicalSourceCreatePO> page = new Page<> (param.getPageNum ( ), param.getPageSize ( ));

        List<String> deptIds = deptFeignClient.getDepSonSelfCodetByCode(param.getDeptIndex()).getData();
        LambdaQueryWrapper<PqTypicalSourceCreatePO> deptLevel = getDeptLevel(param);
        deptLevel.orderByDesc(PqTypicalSourceCreatePO::getProvinceName);

        Page<PqTypicalSourceCreatePO> pqTypicalSourceCreatePOPage = this.getBaseMapper().selectPage(page, deptLevel);

        return pqTypicalSourceCreatePOPage;
    }
    /**
     * 获取当前单位的层级
     */
    public LambdaQueryWrapper<PqTypicalSourceCreatePO> getDeptLevel(SendQueryParam.SendPageParam param) {
        Dept dept = deptFeignClient.getDeptByCode(param.getDeptIndex()).getData();
        List<String> list = Arrays.stream(dept.getPids().split(",")).map(String::trim).collect(Collectors.toList());
        LambdaQueryWrapper<PqTypicalSourceCreatePO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        String beginMonth = formatBeginMonth(param.getSearchBeginTime(), param.getDataType());
        switch (list.size()) {
            //国
            case 1:
                String orgId = getOrgIdForProvince(dept);
                addFiltersForProvince(lambdaQueryWrapper, orgId, beginMonth, param.getSearchState());
                break;
            //省
            case 2:
                addFilters(lambdaQueryWrapper, PqTypicalSourceCreatePO::getProvinceId, param.getDeptIndex(), beginMonth, param.getSearchState());
                break;
            //市
            case 3:
                addFilters(lambdaQueryWrapper, PqTypicalSourceCreatePO::getCityId, param.getDeptIndex(), beginMonth, param.getSearchState());
                break;
            //县
            case 4:
                addFilters(lambdaQueryWrapper, PqTypicalSourceCreatePO::getCountyId, param.getDeptIndex(), beginMonth, param.getSearchState());
                break;
            default:
                break;
        }
        return lambdaQueryWrapper;
    }

    private String formatBeginMonth(String searchBeginTime, String dataType) {
        if (Objects.equals(dataType, "02")) {
            return DateUtil.format(DateUtil.beginOfMonth(DateUtil.parse(searchBeginTime, DatePattern.NORM_MONTH_PATTERN)), DatePattern.NORM_MONTH_PATTERN);
        }
        if (Objects.equals(dataType, "01")) {
            return DateUtil.format(DateUtil.beginOfMonth(DateUtil.parse(searchBeginTime, DatePattern.NORM_YEAR_PATTERN)), DatePattern.NORM_YEAR_PATTERN);
        }
        return searchBeginTime;
    }

    private void addFiltersForProvince(LambdaQueryWrapper<PqTypicalSourceCreatePO> lambdaQueryWrapper, String orgId, String beginMonth, Integer searchState) {
        lambdaQueryWrapper.eq(PqTypicalSourceCreatePO::getProvinceId, orgId)
                .eq(PqTypicalSourceCreatePO::getStatisticalDate, beginMonth)
                .eq(!Objects.isNull(searchState), PqTypicalSourceCreatePO::getIsUploadHead, searchState);
    }

    private void addFilters(LambdaQueryWrapper<PqTypicalSourceCreatePO> lambdaQueryWrapper, SFunction<PqTypicalSourceCreatePO, Object> idFunction, String orgId, String beginMonth, Integer searchState) {
        lambdaQueryWrapper.eq(idFunction, orgId)
                .eq(PqTypicalSourceCreatePO::getStatisticalDate, beginMonth)
                .eq(!Objects.isNull(searchState), PqTypicalSourceCreatePO::getIsUploadHead, searchState);
    }

    private String getOrgIdForProvince(Dept dept) {
        List<Dept> l1 = deptFeignClient.getDirectSonSelf(dept.getId()).getData();
        return l1.stream()
                .filter(o -> !Objects.equals(o.getId(), dept.getId()))
                .findFirst()
                .map(Dept::getCode)
                .orElse(null);
    }

    @Override
    public String send(UploadParam uploadParam) {
        LocalDate localDate = LocalDate.parse(uploadParam.getTime(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));


        List<PqTypicalSourceCreatePO> list;
        //指定数据上送,不管之前有没有上送,都重新上送一次
        //(预防之前送上过,修改数据后需要再次上送)
        if (CollectionUtil.isNotEmpty(uploadParam.getList())){
            list = this.lambdaQuery()
                    .eq(PqTypicalSourceCreatePO::getComputeDate,uploadParam.getTime())
                    .in(PqTypicalSourceCreatePO::getId,uploadParam.getList())
                    .isNotNull(PqTypicalSourceCreatePO::getComputeDate)
                    .in(PqTypicalSourceCreatePO::getStatisticalLevel,Stream.of("3","4","5").collect(Collectors.toList()))
                    .list();
        }
        //未指定数据上送,则将所有未上送的数据,上送上去
        else {
            list = this.lambdaQuery()
                    .eq(PqTypicalSourceCreatePO::getComputeDate,uploadParam.getTime())
                    .isNotNull(PqTypicalSourceCreatePO::getComputeDate)
                    .in(PqTypicalSourceCreatePO::getStatisticalLevel, Stream.of("3","4","5").collect(Collectors.toList()))
                    .list();
        }

        //以尺寸100分片
        List<List<PqTypicalSourceCreatePO>> partition = ListUtils.partition(list, 100);
        StrBuilder resultLog = new StrBuilder();
        AtomicBoolean resultFlag = new AtomicBoolean(true);
        for (int i = 0; i < partition.size(); i++) {
            List<PqTypicalSourceCreateDTO> dtoList = BeanUtil.copyToList(partition.get(i), PqTypicalSourceCreateDTO.class);
            SendParam sendParam = new SendParam();
            sendParam.setStats(dtoList);
            sendParam.setStatisticalDate(partition.get(i).get(0).getComputeDate());
            if(i == 0){
                sendParam.setIsAppend("0");
            }else if(i==partition.size()-1){
                sendParam.setIsAppend("2");
            }else {
                sendParam.setIsAppend("1");
            }
            Map<String, String> send = GwSendUtil.send(sendParam, GWSendEnum.TYPICAL_SOURCE);
            List<String> trIds = dtoList.stream().map(PqTypicalSourceCreateDTO::getId).distinct().collect(Collectors.toList());
            returnInformation(i, trIds, send,resultLog, resultFlag, localDate);
        }
        if (resultFlag.get()) {
            resultLog.append(" 上送" + list.size() + "条数据成功");
            assUploadLog(localDate, resultLog, resultFlag);
        }
        return "成功";

    }

    private void assUploadLog(LocalDate statisticDate, StrBuilder msg, AtomicBoolean resultFlag){
        RUploadDataLog rUploadDataLog = new RUploadDataLog();
        rUploadDataLog.setStatisticDate(statisticDate);
        rUploadDataLog.setBigType(0);
        rUploadDataLog.setSmallType(3);
        rUploadDataLog.setCreateTime(LocalDateTime.now());
        rUploadDataLog.setResult(resultFlag.get()?1:0);
        rUploadDataLog.setResultMsg(msg.toString());
        irUploadDataLogService.saveOrUpdateByMultiId(rUploadDataLog);
    }

    /**
     * 国网上送返回信息
     *
     * @param ids
     * @param send
     * @return
     */
    private void returnInformation(Integer step, List<String> ids, Map<String, String> send, StrBuilder resultLog, AtomicBoolean resultFlag, LocalDate localDate) {
        int start = step * 100;
        int end = (step + 1) * 100;
        if (send.containsKey("succeed")) {
            String succeed = send.get("succeed");
            if (succeed.contains("\\\"")) {
                succeed = succeed.replace("\\\"", "\"");
            }
            Map mapData = JSON.parseObject(succeed, Map.class);
            String status = mapData.get("status").toString();

            if ("000000".equals(status)) {
                //修改数据上送状态
                updateState(ids);
                String result = mapData.get("result").toString();
                Map mapCount = JSON.parseObject(result, Map.class);
                String count = mapCount.get("count").toString();

            } else {
                resultFlag.set(false);
                String errors = mapData.get("errors").toString();
                String errorMsg = " 上送" + start + "条至" + end + "条数据,上送失败:" + status + "_" + errors + " ;";
                resultLog.append(errorMsg);
                assUploadLog(localDate, resultLog, resultFlag);
                throw new BusinessException(errorMsg);
            }
        } else {
            resultFlag.set(false);
            resultLog.append(" 上送" + start + "条至" + end + "条数据网络异常;");
            assUploadLog(localDate, resultLog, resultFlag);
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }


    }

    private void updateState(List<String> ids) {
        LambdaUpdateWrapper<PqTypicalSourceCreatePO> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.in(PqTypicalSourceCreatePO::getId, ids)
                .set(PqTypicalSourceCreatePO::getIsUploadHead, 1);
        this.update(lambdaUpdateWrapper);
    }
}
