package com.tofly.analyse.service.impl;


import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.supermap.data.*;
import com.tofly.analyse.entity.PipeCountDto;
import com.tofly.analyse.entity.SpaceCountDto;
import com.tofly.analyse.entity.SubtypeCountDto;
import com.tofly.analyse.entity.em.SpaceCountEnum;
import com.tofly.analyse.mapper.SpaceCountMapper;
import com.tofly.analyse.service.SpaceCountService;
import com.tofly.analyse.util.analysis.CamelToUtil;
import com.tofly.analyse.util.analysis.DatasourceConfig;
import com.tofly.common.core.entity.ResultRespone;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author zhoux
 */
@AllArgsConstructor
@Service("spaceCountService")
public class SpaceCountServiceImpl implements SpaceCountService {

    @Autowired
    private DatasourceConfig datasourceConfig;

    @Autowired
    private SpaceCountMapper spaceCountMapper;

    @Override
    public ResultRespone getSpaceCount(SpaceCountDto spaceCountDto) {
        if (CollUtil.isNotEmpty(spaceCountDto.getDatasetNames())) {
            if(CollUtil.isNotEmpty(spaceCountDto.getGeoJSON())){
                ResultRespone objectResultRespone = getObjectResultRespone(spaceCountDto);
                return  objectResultRespone;
            }else{
                Map<String, Object> dataMap = new HashMap<>();
                for (String d : spaceCountDto.getDatasetNames()) {
                    Map<String,Object> param=new HashMap<>();
                    param.put("tableName",d);
                    if (CollUtil.isNotEmpty(spaceCountDto.getFiled())) {
                        param.put("fileds",spaceCountDto.getFiled());
                    }
                    if (CollUtil.isNotEmpty(spaceCountDto.getQueryParameter())) {
                        param.put("queryParameter",spaceCountDto.getQueryParameter().get(d));
                    }
                    if (spaceCountDto.getType()!=null) {
                        param.put("type",spaceCountDto.getType());
                    }
                    if (spaceCountDto.getCountFiled()!=null) {
                        param.put("countFiled",spaceCountDto.getCountFiled().get(d));
                    }
                    List<String> spaceCountData = spaceCountMapper.getSpaceCountData(param);
                    dataMap.put(d,spaceCountData);
                }
                return ResultRespone.success(dataMap);
            }
        } else {
            return ResultRespone.failed("图层名不能为空");
        }
    }

    @Override
    public Page<Map> getPipeCountData(Page page,PipeCountDto dto) {
        return page.setRecords(this.spaceCountMapper.getPipeCountData(page,dto));
    }

    @Override
    public List<Map> getSubtypeCount(SubtypeCountDto subtypeCountDto) {
        List<Map> result=new ArrayList<>();
        if(StringUtils.isNotBlank(subtypeCountDto.getDatasetName())){
            String[] splits = subtypeCountDto.getDatasetName().split(",");
            for(String s:splits){
                Map<String,Object> param=new HashMap<>();
                param.put("datasetName",s);
                if(CollUtil.isNotEmpty(subtypeCountDto.getFiled())){
                    Object o = subtypeCountDto.getFiled().get(s);
                    if(o!=null){
                        param.put("filed",o.toString());
                    }
                }
                if(CollUtil.isNotEmpty(subtypeCountDto.getQueryParameter())){
                    if(subtypeCountDto.getQueryParameter().get(s)!=null){
                        param.put("queryParameter",subtypeCountDto.getQueryParameter().get(s).toString());
                    }
                }
                List<Map> subtypeCountData = this.spaceCountMapper.getSubtypeCountData(param);
                if(CollUtil.isNotEmpty(subtypeCountData)){
                    subtypeCountData.forEach(d->{
                        d.put("type",s);
                        result.add(d);
                    });
                }
            }
        }
        return result;
    }

    private ResultRespone getObjectResultRespone(SpaceCountDto spaceCountDto) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> resultMap = new ArrayList<>();
        Workspace workspace = new Workspace();
        Datasource datasource = null;
        try {
            datasource = datasourceConfig.getDatasource(workspace);
            Datasets datasets = datasource.getDatasets();
            for (String d : spaceCountDto.getDatasetNames()) {
                if (datasets.contains(d)) {
                    DatasetVector datasetVector = (DatasetVector) datasets.get(d);
                    QueryParameter queryParameter = getQueryParameter(spaceCountDto, d);
                    Recordset recordset = datasetVector.query(queryParameter);
                    recordset.moveFirst();
                    FieldInfos fieldInfos = recordset.getFieldInfos();
                    FieldInfo[] fieldInfos1 = fieldInfos.toArray();
                    while (!recordset.isEOF()) {
                        Map<String, Object> dataMap = new HashMap<>();
                        for (FieldInfo f : fieldInfos1) {
                            Object fieldValue = recordset.getFieldValue(f.getName());
                            dataMap.put(f.getName(), fieldValue);
                        }
                        resultMap.add(dataMap);
                        recordset.moveNext();
                    }
                    if (CollUtil.isNotEmpty(resultMap)) {
                        List<Map<String,Object>> datas=new ArrayList<>();
                        if (CollUtil.isNotEmpty(spaceCountDto.getFiled())) {
                            Map<String, List<Map<String, Object>>> collect = resultMap.stream().collect(
                                    Collectors.groupingBy(item ->{
                                        StringBuffer stringBuffer=new StringBuffer();
                                        for(int i=0;i<spaceCountDto.getFiled().size();i++){
                                            stringBuffer.append(item.get(spaceCountDto.getFiled().get(i).toString()));
                                            if(i!=spaceCountDto.getFiled().size()-1){
                                                stringBuffer.append(",");
                                            }
                                        }
                                        return stringBuffer.toString();
                                    })
                            );
                            collect.forEach((k, v) -> {
                                Map<String, Object> filedMap = new HashMap<>();
                                String[] split = k.split(",");
                                for(int i=0;i<split.length;i++){
                                    filedMap.put(CamelToUtil.underlineToCamel(spaceCountDto.getFiled().get(i)),split[i]);
                                }
                                if (spaceCountDto.getType() != null && spaceCountDto.getType() == 0 && CollUtil.isNotEmpty(spaceCountDto.getCountFiled())) {
                                    AtomicReference<Double> total = getDoubleAtomicReference(spaceCountDto, d, resultMap);
                                    filedMap.put("len", total.get().toString());
                                }
                                filedMap.put("num", v.size());
                                datas.add(filedMap);
                            });
                        } else {
                            Map<String, Object> dataMap = new HashMap<>();
                            if (spaceCountDto.getType() != null && spaceCountDto.getType() == 0 && CollUtil.isNotEmpty(spaceCountDto.getCountFiled())) {
                                AtomicReference<Double> total = getDoubleAtomicReference(spaceCountDto, d, resultMap);
                                dataMap.put("len", total.get().toString());
                            }
                            dataMap.put("num", resultMap.size());
                            datas.add(dataMap);
                        }
                        result.put(d, datas);
                    } else {
                        result.put(d, null);
                    }
                    recordset.dispose();
                } else {
                    return ResultRespone.failed("不存在此图层");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (datasource.isOpened())
                datasource.close();
            workspace.close();
        }
        return ResultRespone.success(result);
    }

    private static AtomicReference<Double> getDoubleAtomicReference(SpaceCountDto spaceCountDto, String d, List<Map<String, Object>> v) {
        AtomicReference<Double> total = new AtomicReference<>(0.0);
        v.forEach(r -> {
            Object length = r.get(spaceCountDto.getCountFiled().get(d));
            if (length != null) {
                total.updateAndGet(v1 -> v1 + Double.parseDouble(length.toString()));
            }
        });
        return total;
    }

    private static QueryParameter getQueryParameter(SpaceCountDto spaceCountDto, String d) {
        QueryParameter queryParameter = new QueryParameter();
        queryParameter.setCursorType(CursorType.STATIC);
        if (CollUtil.isNotEmpty(spaceCountDto.getQueryParameter())) {
            Map<String, Object> queryParameter1 = spaceCountDto.getQueryParameter();
            Object o = queryParameter1.get(d);
            if (o != null) {
                queryParameter.setAttributeFilter(o.toString());
            }
        }
        if (CollUtil.isNotEmpty(spaceCountDto.getGeoJSON())) {
            queryParameter.setSpatialQueryMode(SpatialQueryMode.CONTAIN);
            Point2Ds point2Ds = new Point2Ds();
            spaceCountDto.getGeoJSON().forEach(g -> {
                double x = Double.parseDouble(g.get(SpaceCountEnum.X.getCode()).toString());
                double y = Double.parseDouble(g.get(SpaceCountEnum.Y.getCode()).toString());
                Point2D point2D = new Point2D(x, y);
                point2Ds.add(point2D);
            });
            GeoRegion geoRegion = new GeoRegion(point2Ds);
            queryParameter.setSpatialQueryObject(geoRegion);
        }
        return queryParameter;
    }
}