package cn.cslg.pas.service;

import cn.cslg.pas.common.core.base.Constants;
import cn.cslg.pas.common.model.dto.PatentQueryFieldSourceDTO;
import cn.cslg.pas.common.model.dto.analysis.AnalysisItemResultDTO;
import cn.cslg.pas.common.model.dto.analysis.SchemaDimensionDTO;
import cn.cslg.pas.common.model.dto.analysis.SourceDataDTO;
import cn.cslg.pas.common.model.dto.analysis.SourceMinAndMaxDataDTO;
import cn.cslg.pas.common.model.vo.PatentQueryFieldSourceVO;
import cn.cslg.pas.common.model.vo.SearchSourceDataVO;
import cn.cslg.pas.common.model.vo.SourceDataVO;
import cn.cslg.pas.common.utils.*;
import cn.cslg.pas.domain.CustomAnalysisItem;
import cn.cslg.pas.domain.CustomAnalysisItemSource;
import cn.cslg.pas.domain.ProjectFieldExpand;
import cn.cslg.pas.mapper.CustomAnalysisItemSourceMapper;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 自定义分析项目数据源 服务实现类
 * </p>
 *
 * @author 王岩
 * @since 2021-12-24
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class CustomAnalysisItemSourceService extends ServiceImpl<CustomAnalysisItemSourceMapper, CustomAnalysisItemSource> {

    private final PatentService patentService;
    private final CacheUtils cacheUtils;
    private final ProjectFieldTreeService projectFieldTreeService;
    private final ProjectFieldService projectFieldService;

    public SourceDataDTO getItemSourceData(CustomAnalysisItem customAnalysisItem) {
        SourceDataDTO sourceDataDTO = new SourceDataDTO();
        SchemaDimensionDTO schema = customAnalysisItem.getSchema();
        sourceDataDTO.setX(this.setReturnData(this.getItemSourceList(customAnalysisItem.getUid(), "x", schema.getX().getField(), schema.getX().getExpand())));
        sourceDataDTO.setY(this.setReturnData(this.getItemSourceList(customAnalysisItem.getUid(), "y", schema.getY().getField(), schema.getY().getExpand())));
        return sourceDataDTO;
    }

    public List<CustomAnalysisItemSource> setReturnData(List<CustomAnalysisItemSource> list) {
        list.forEach(item -> {
            item.setUid(null);
            item.setDimension(null);
            item.setFieldId(null);
            item.setExpandId(null);
            item.setCreateTime(null);
            item.setUpdateTime(null);
            item.setStatus(null);
            item.setId(null);
            item.setCreateBy(null);
            if (StringUtils.isNotEmpty(item.getMaxData())) {
                item.setMax(JsonUtils.jsonToPojo(item.getMaxData(), SourceMinAndMaxDataDTO.class));
                item.setMaxData(null);
            }
            if (StringUtils.isNotEmpty(item.getMinData())) {
                item.setMin(JsonUtils.jsonToPojo(item.getMinData(), SourceMinAndMaxDataDTO.class));
                item.setMinData(null);
            }
        });
        return list;
    }

    public List<CustomAnalysisItemSource> getItemSourceList(String uid, String dimension, Integer fieldId, Integer expandId) {
        LambdaQueryWrapper<CustomAnalysisItemSource> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CustomAnalysisItemSource::getUid, uid);
        queryWrapper.eq(CustomAnalysisItemSource::getDimension, dimension);
        queryWrapper.eq(CustomAnalysisItemSource::getFieldId, fieldId);
        queryWrapper.eq(CustomAnalysisItemSource::getExpandId, expandId);
        return this.list(queryWrapper);
    }

    private PatentQueryFieldSourceVO getPatentQueryFieldSourceVO(Integer fieldId, Integer expandId, Integer projectId, Integer type, Integer end) {
        PatentQueryFieldSourceVO params = new PatentQueryFieldSourceVO();
        params.setKey(String.format("%s-%s", fieldId, expandId));
        params.setProjectId(projectId);
        params.setType(String.valueOf(type));
        params.setCurrent((long) 1);
        params.setSize((long) end);
        if (type >= 90) {
            params.setType("query");
        } else {
            params.setType(String.valueOf(type));
        }
        return params;
    }

    private void setTreeNodeCountDataForRedis(List<Integer> patentIds, SearchSourceDataVO searchSourceDataVO) {
        for (int i = 0; i < 2; i++) {
            List<AnalysisItemResultDTO> resultList = cacheUtils.getAnalysisCountV2(searchSourceDataVO.getPatentKey(), searchSourceDataVO.getFieldId(), i);
            if (resultList.size() == 0) {
                List<PatentQueryFieldSourceDTO> dataList = patentService.getPatentAttributeSourceList(this.getPatentQueryFieldSourceVO(searchSourceDataVO.getFieldId(), i, searchSourceDataVO.getProjectId(), searchSourceDataVO.getType(), 0), patentIds);
                for (PatentQueryFieldSourceDTO item : dataList) {
                    cacheUtils.setAnalysisCountV2(searchSourceDataVO.getPatentKey(), searchSourceDataVO.getFieldId(), i, item.getValue(), item.getIds());
                }
            }
        }
    }

    private List<AnalysisItemResultDTO> setCommonDataCountDataForRedis(List<Integer> patentIds, SearchSourceDataVO searchSourceDataVO) {
        long end = searchSourceDataVO.getNum();
        List<AnalysisItemResultDTO> resultList = cacheUtils.getAnalysisCountV2(searchSourceDataVO.getPatentKey(), searchSourceDataVO.getFieldId(), searchSourceDataVO.getExpandId());
        if (resultList.size() == 0) {
            List<PatentQueryFieldSourceDTO> dataList1 = patentService.getPatentAttributeSourceList(this.getPatentQueryFieldSourceVO(searchSourceDataVO.getFieldId(), searchSourceDataVO.getExpandId(), searchSourceDataVO.getProjectId(), searchSourceDataVO.getType(), 0), patentIds);
            for (PatentQueryFieldSourceDTO item : dataList1) {
                cacheUtils.setAnalysisCountV2(searchSourceDataVO.getPatentKey(), searchSourceDataVO.getFieldId(), searchSourceDataVO.getExpandId(), item.getLabel(), item.getIds());
            }
            if (searchSourceDataVO.getExpandId().equals(18)) {
                List<AnalysisItemResultDTO> tempList = cacheUtils.getAnalysisCountV2(searchSourceDataVO.getPatentKey(), searchSourceDataVO.getFieldId(), 19);
                if (tempList.size() == 0) {
                    for (int i = 0; i < 2; i++) {
                        List<PatentQueryFieldSourceDTO> dataList2 = patentService.getPatentAttributeSourceList(this.getPatentQueryFieldSourceVO(searchSourceDataVO.getFieldId(), 19 + i, searchSourceDataVO.getProjectId(), searchSourceDataVO.getType(), 0), patentIds);
                        for (PatentQueryFieldSourceDTO item : dataList2) {
                            cacheUtils.setAnalysisCountV2(searchSourceDataVO.getPatentKey(), searchSourceDataVO.getFieldId(), 19, item.getLabel(), item.getIds());
                        }
                    }
                }
            }
            resultList = cacheUtils.getAnalysisCountV2(searchSourceDataVO.getPatentKey(), searchSourceDataVO.getFieldId(), searchSourceDataVO.getExpandId());
        }
        return resultList.stream().sorted(Comparator.comparing(AnalysisItemResultDTO::getCount).reversed()).limit(end).collect(Collectors.toList());
    }

    /**
     * @description 图标分析模块 数据获取方法(一维数据，二位数据的下拉选项)
     */
    public String getSourceData2(SearchSourceDataVO searchSourceDataVO) {
        //从Redis中获取选中ID的缓存
        String id = cacheUtils.getSelectPatentIds(searchSourceDataVO.getPatentKey());
        //为空报错
        if (StringUtils.isEmpty(id)) {
            return Response.error(ResponseEnum.QUERY_CACHE_ERROR);
        }
        //获取前端选择的条数范围(10,20,30,40,50,全部)
        long end = searchSourceDataVO.getNum();
        List<CustomAnalysisItemSource> list = new ArrayList<>();
        //拆分出选中的IDList
        List<Integer> patentIds = StringUtils.changeStringToInteger(id, ",");
        //如果选中的数据类型是 树(6) 执行分支
        if (searchSourceDataVO.getType().equals(6)) {
            // TODO: 2022/9/26 树型数据 未解析逻辑 沈永艺
            this.setTreeNodeCountDataForRedis(patentIds, searchSourceDataVO);
            return Response.success(projectFieldTreeService.getProjectFieldTreeNodeByFieldId(searchSourceDataVO.getFieldId()));
        }
        //非树型
        switch (searchSourceDataVO.getPtype()) {
            //(部,大类,小类,大组,小组) (当前,标准,合并后) (国家,省,市)
            case 1:
                // TODO: 2022/9/26 处理条件 未解析逻辑 沈永艺
                List<AnalysisItemResultDTO> resultList = this.setCommonDataCountDataForRedis(patentIds, searchSourceDataVO);
                for (AnalysisItemResultDTO item : resultList) {
                    CustomAnalysisItemSource customAnalysisItemSource = new CustomAnalysisItemSource();
                    customAnalysisItemSource.setStatus(null);
                    customAnalysisItemSource.setCreateTime(null);
                    customAnalysisItemSource.setUpdateTime(null);
                    customAnalysisItemSource.setName(item.getName());
                    list.add(customAnalysisItemSource);
                }
                break;
            //年份（月,季度,半年,1年,2年,3年,5年）
            case 2:
                //获取PType为2的数据
                List<ProjectFieldExpand> expandList = projectFieldService.getProjectFieldExpand().stream().filter(item -> item.getPtype().equals(searchSourceDataVO.getPtype())).collect(Collectors.toList());
                //获取属性的名称
                String dateType = expandList.stream().filter(item -> item.getId().equals(searchSourceDataVO.getExpandId())).findFirst().orElse(new ProjectFieldExpand()).getName();
                //用名称获取偏移的数字 (注：这里的偏移均是指减去多少个月 例:2022-01-01 偏移-12 为 2021-01-01)
                Integer offset = Constants.DATE_OFFSET.get(dateType);
                //根据FieldId的不同获取选中IDList中的对应日期 fieldId说明: 25申请日 26公开日 27公开授权日
                //1.获取最小的日期
                Date endDate = patentService.getDateTime(id, searchSourceDataVO.getFieldId(), "min");
                //2.获取最大的日期
                Date startTime = patentService.getDateTime(id, searchSourceDataVO.getFieldId(), "max");
                //创建偏移数据
                Date endTime = DateUtil.offsetMonth(startTime, offset);
                int index = 0;
                /*
                    do while的判断规则: 1.当最大日期比最小日期小 &&  2.循环次数超出所传入范围
                 */
                do {
                    //装填数据
                    CustomAnalysisItemSource customAnalysisItemSource = new CustomAnalysisItemSource();
                    //依据偏移月数的不同 获取不同的对应数据
                    customAnalysisItemSource.setName(DateUtils.getDateSourceName(startTime, endTime, offset, index++));
                    customAnalysisItemSource.setStatus(null);
                    customAnalysisItemSource.setCreateTime(null);
                    customAnalysisItemSource.setUpdateTime(null);
                    //重设最大日期
                    startTime = DateUtil.offsetMonth(startTime, offset);
                    //重设偏移数据
                    endTime = DateUtil.offsetMonth(endTime, offset);
                    //向List中加入所需数据 用于返回前台展示
                    list.add(customAnalysisItemSource);
                } while (DateUtil.compare(DateUtil.offsetMonth(startTime, offset * -1), endDate) > 0 && index < end);
                break;
            //自定义
            case 3:
            case 4:
                // TODO: 2022/9/26 自定义字段 未解析逻辑 沈永艺
                list = this.getItemSourceList(searchSourceDataVO.getUid(), searchSourceDataVO.getDimension(), searchSourceDataVO.getFieldId(), searchSourceDataVO.getExpandId());
                break;
        }
        return Response.success(this.setReturnData(list));
    }

    @Transactional(rollbackFor = Exception.class)
    public void edit(CustomAnalysisItem customAnalysisItem) {
        SourceDataVO x = new SourceDataVO();
        SourceDataVO y = new SourceDataVO();
        SourceDataDTO sourceDataDTO = customAnalysisItem.getSource();
        if (customAnalysisItem.getSchema().getX().getPtype().equals(3) || customAnalysisItem.getSchema().getX().getPtype().equals(4) || customAnalysisItem.getSchema().getX().getType().equals(6)) {
            x.setUid(customAnalysisItem.getUid());
            x.setDimension("x");
            x.setFieldId(customAnalysisItem.getSchema().getX().getField());
            x.setExpandId(customAnalysisItem.getSchema().getX().getExpand());
            x.setSource(sourceDataDTO.getX());
            this.updateSource(x);
        }
        if (customAnalysisItem.getSchema().getY().getPtype().equals(3) || customAnalysisItem.getSchema().getY().getPtype().equals(4) || customAnalysisItem.getSchema().getY().getType().equals(6)) {
            y.setUid(customAnalysisItem.getUid());
            y.setDimension("y");
            y.setFieldId(customAnalysisItem.getSchema().getY().getField());
            y.setExpandId(customAnalysisItem.getSchema().getY().getExpand());
            y.setSource(sourceDataDTO.getY());
            this.updateSource(y);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateSource(SourceDataVO sourceDataVO) {
        this.remove(Wrappers.<CustomAnalysisItemSource>lambdaQuery().eq(CustomAnalysisItemSource::getUid, sourceDataVO.getUid()).eq(CustomAnalysisItemSource::getDimension, sourceDataVO.getDimension()));
        List<CustomAnalysisItemSource> list = new ArrayList<>();
        sourceDataVO.getSource().forEach(source -> {
            if (StringUtils.isNotNull(source.getMax())) {
                source.setMaxData(JsonUtils.objectToJson(source.getMax()));
            }
            if (StringUtils.isNotNull(source.getMin())) {
                source.setMinData(JsonUtils.objectToJson(source.getMin()));
            }
            source.setFieldId(sourceDataVO.getFieldId());
            source.setExpandId(sourceDataVO.getExpandId());
            source.setCreateBy(StpUtil.getLoginIdAsInt());
            source.setDimension(sourceDataVO.getDimension());
            source.setUid(sourceDataVO.getUid());
            list.add(source);
        });
        this.saveOrUpdateBatch(list);
    }

    public void deleteByUid(String uid) {
        this.remove(Wrappers.<CustomAnalysisItemSource>lambdaQuery().eq(CustomAnalysisItemSource::getUid, uid));
    }
}
