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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
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.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.upload.RUploadSubstationStatisticalDataDMapper;
import com.njcn.harmonic.pojo.dto.upload.SubstationQualityStatisticsDTO;
import com.njcn.harmonic.pojo.param.UploadDataParam;
import com.njcn.harmonic.pojo.param.UploadParam;
import com.njcn.harmonic.pojo.po.upload.RUploadDataLog;
import com.njcn.harmonic.pojo.po.upload.RUploadSubstationStatisticalDataD;
import com.njcn.harmonic.pojo.vo.upload.UploadSubstationStatisticalDataVo;
import com.njcn.harmonic.service.upload.IRUploadDataLogService;
import com.njcn.harmonic.service.upload.ISubstationStatisticalDataService;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.po.Dept;
import com.njcn.web.enums.GWSendEnum;
import com.njcn.web.factory.PageFactory;
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.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * <p>
 * 主配网变电站监测统计数据-日表 服务实现类
 * </p>
 *
 * @author xuyang
 * @since 2023-12-08
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class RSubstationStatisticalDataServiceImpl extends ServiceImpl<RUploadSubstationStatisticalDataDMapper, RUploadSubstationStatisticalDataD> implements ISubstationStatisticalDataService {

    private final DeptFeignClient deptFeignClient;

    private final IRUploadDataLogService irUploadDataLogService;

    @Override
    public Page<UploadSubstationStatisticalDataVo> getSubstationStatisticalData(UploadDataParam param) {
        LambdaQueryWrapper<RUploadSubstationStatisticalDataD> lambdaQueryWrapper = getDeptLevel(param);
        //默认按照省名称排序
        lambdaQueryWrapper.orderByDesc(RUploadSubstationStatisticalDataD::getProvinceName);
        Page<RUploadSubstationStatisticalDataD> page = this.page(new Page<>(PageFactory.getPageNum(param), PageFactory.getPageSize(param)), lambdaQueryWrapper);
        List<UploadSubstationStatisticalDataVo> voList = BeanUtil.copyToList(page.getRecords(), UploadSubstationStatisticalDataVo.class);

        Page<UploadSubstationStatisticalDataVo> pageVo = new Page<>();
        pageVo.setTotal(page.getTotal());
        pageVo.setPages(page.getPages());
        pageVo.setSize(page.getSize());
        pageVo.setRecords(voList);
        pageVo.setCurrent(page.getCurrent());
        return pageVo;
    }

    @Override
    public String uploadSubstationStatisticalData(UploadParam param) {
        List<RUploadSubstationStatisticalDataD> list;
        //指定数据上送,不管之前有没有上送,都重新上送一次
        //(预防之前上送过,修改数据后需要再次上送)
        if (CollUtil.isNotEmpty(param.getList())){
            list = this.lambdaQuery()
                    .in(RUploadSubstationStatisticalDataD::getId,param.getList())
                    .eq(RUploadSubstationStatisticalDataD::getComputeDate,param.getTime())
                    .list();
        }
        //未指定数据上送,则将所有未上送的数据,上送上去
        else {
            list = this.lambdaQuery()
                    .eq(RUploadSubstationStatisticalDataD::getComputeDate,param.getTime())
                    .list();
        }

        if(CollUtil.isEmpty(list)){
            throw new BusinessException("数据为空，请联系管理员排查");
        }

        //以尺寸100分片
        List<List<RUploadSubstationStatisticalDataD>> partition = ListUtils.partition(list, 100);
        StrBuilder resultLog = new StrBuilder();
        AtomicBoolean resultFlag = new AtomicBoolean(true);
        //分片上传
        LocalDate localDate = LocalDate.parse(partition.get(0).get(0).getComputeDate(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));
        for (int i = 0; i < partition.size(); i++) {
            List<RUploadSubstationStatisticalDataD> collect = partition.get(i).stream().peek(item -> {
                item.setStatisticalDate(item.getComputeDate().substring(0, 7));
            }).collect(Collectors.toList());
            List<SubstationQualityStatisticsDTO> dtoList = BeanUtil.copyToList(collect, SubstationQualityStatisticsDTO.class);
            SendParam sp = new SendParam();
            sp.setStats(dtoList);
            sp.setStatisticalDate(partition.get(i).get(0).getComputeDate());
            if(i == 0){
                sp.setIsAppend("0");
            }else if(i==partition.size()-1){
                sp.setIsAppend("2");
            }else {
                sp.setIsAppend("1");
            }
            //上送数据
            Map<String, String> send = GwSendUtil.send(sp, GWSendEnum.SUBSTATION_MONITOR);
            //获取返回结果
            List<String> l = dtoList.stream().map(SubstationQualityStatisticsDTO::getId).collect(Collectors.toList());
            returnInformation(i,l,send,resultLog,resultFlag,localDate);
        }

        if(resultFlag.get()){
            resultLog.append(" 上送" +list.size()+ "条数据成功;");
            assUploadLog(localDate,resultLog,resultFlag);
        }
        return "上送成功:成功数据" + list.size() + "条";
    }


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

    /**
     * 获取当前单位的层级
     */
    public LambdaQueryWrapper<RUploadSubstationStatisticalDataD> getDeptLevel(UploadDataParam param) {
        Dept dept = deptFeignClient.getDeptByCode(param.getOrgId()).getData();
        List<String> list = Arrays.stream(dept.getPids().split(",")).map(String::trim).collect(Collectors.toList());
        LambdaQueryWrapper<RUploadSubstationStatisticalDataD> 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, RUploadSubstationStatisticalDataD::getProvinceId, param.getOrgId(), beginMonth, param.getSearchState());
                break;
            //市
            case 3:
                addFilters(lambdaQueryWrapper, RUploadSubstationStatisticalDataD::getCityId, param.getOrgId(), beginMonth, param.getSearchState());
                break;
            //县
            case 4:
                addFilters(lambdaQueryWrapper, RUploadSubstationStatisticalDataD::getCountyId, param.getOrgId(), beginMonth, param.getSearchState());
                break;
            default:
                break;
        }
        lambdaQueryWrapper.eq(RUploadSubstationStatisticalDataD::getStatisticalType,param.getDataType());
        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);
        }else if(Objects.equals(dataType, "01")){
            return DateUtil.format(DateUtil.parse(searchBeginTime,DatePattern.NORM_DATE_PATTERN),DatePattern.NORM_YEAR_PATTERN);
        }
        return searchBeginTime;
    }

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

    private void addFilters(LambdaQueryWrapper<RUploadSubstationStatisticalDataD> lambdaQueryWrapper, SFunction<RUploadSubstationStatisticalDataD, Object> idFunction, String orgId, String beginMonth, Integer searchState) {
        lambdaQueryWrapper.eq(idFunction, orgId)
                .eq(RUploadSubstationStatisticalDataD::getStatisticalDate, beginMonth)
                .eq(!Objects.isNull(searchState), RUploadSubstationStatisticalDataD::getUploadStatus, 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);
    }

    /**
     * 国网上送返回信息
     *
     * @param step  分片上传当前阶段
     * @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("当前时间段国网上送请求过多，请稍后再试");
        }
    }


    /**
     * 修改上送信息状态
     * @param ids id集合
     */
    private void updateState(List<String> ids) {
        LambdaUpdateWrapper<RUploadSubstationStatisticalDataD> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.in(RUploadSubstationStatisticalDataD::getId, ids)
                .set(RUploadSubstationStatisticalDataD::getUploadStatus, 1);
        this.update(lambdaUpdateWrapper);
    }
}
