package cn.edu.whu.boot.collection.service.impl;

import cn.edu.whu.boot.allocation.exceptions.InvalidShapefileException;
import cn.edu.whu.boot.collection.domain.MultimediaItem;
import cn.edu.whu.boot.collection.domain.TaskSelectId;
import cn.edu.whu.boot.collection.dto.GeometryType;
import cn.edu.whu.boot.collection.dto.SqlEnity;
import cn.edu.whu.boot.collection.mapper.UpdateMapper;
import cn.edu.whu.boot.collection.service.IBaseService;
import cn.edu.whu.boot.collection.service.IMultimediaService;
import cn.edu.whu.boot.collection.service.ITaskSelectIdService;
import cn.edu.whu.boot.collection.service.ImportService;
import cn.edu.whu.boot.common.domain.CommonConstant;
import cn.edu.whu.boot.common.domain.ResultMessage;
import cn.edu.whu.boot.common.utils.collection.PostgreSqlUtil;
import cn.edu.whu.boot.common.utils.collection.TableOperationUtil;
import cn.edu.whu.boot.common.utils.xml.GenerateSqlUtil;
import cn.edu.whu.boot.xml.domain.Task;
import cn.edu.whu.boot.xml.xmlreader.bean.Config;
import cn.edu.whu.boot.xml.xmlreader.bean.Field;
import cn.edu.whu.boot.xml.xmlreader.bean.Table;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.io.ParseException;
import org.geotools.geojson.geom.GeometryJSON;
import java.io.StringWriter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ImportServiceImpl implements ImportService {

    @Autowired
    private IBaseService baseService;

    @Autowired
    private IMultimediaService multimediaService;

    @Autowired
    private ITaskSelectIdService taskSelectIdService;

    @Autowired
    private UpdateMapper updateMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public ResultMessage taskTableDataInsert (Task srcTask, Task destTask, String srcTableName, String destTableName,
                                              int selectType, int selectDataNum, String whereClause, String fieldMapping) throws IOException{
        String srcTableNameInDb = PostgreSqlUtil.buildTableNameString(srcTask.getDatabaseName(), srcTableName, false, false);
        Table srcRootTable = JSON.toJavaObject(JSON.parseObject(srcTask.getConfig()), Config.class).getRootTables().get(srcTableName);
        Integer srcTaskId = srcTask.getId();
        Integer destTaskId = destTask.getId();
        String srcPrimaryKey = TableOperationUtil.getPrimaryKey(srcRootTable);

        List<TaskSelectId> taskSelectIdList = taskSelectIdService.getTaskSelectIdByTaskIdAndTableName(srcTaskId, srcTableName, destTaskId, destTableName);
        List<Integer> selectIdList = getSelectIdList(taskSelectIdList);
        // 当前剩余数据的个数
        int remainingCount = Integer.parseInt(baseService.getDataCount(srcTableNameInDb).toString()) - selectIdList.size();
        // 通过 selectType 字段判断是否此次操作的类型
        if(selectType == 0){
            selectDataNum = remainingCount;
        }
        else if(selectType == 2){
            selectDataNum = (int)(remainingCount * (selectDataNum / 100.0));
        }
        if (selectDataNum == 0) {
            selectDataNum = remainingCount;
        }
        List<Map<String,Object>> srcRootTableList = baseService.randomSelectDataIdNotInList(srcTableNameInDb, PostgreSqlUtil.transformString(srcPrimaryKey),
                                                                   CollectionUtils.isEmpty(selectIdList) ? null : selectIdList, selectDataNum, whereClause);
        if (CollectionUtils.isEmpty(srcRootTableList)){
            return new ResultMessage(true,"无数据可抽查",400);
        }
        Table destRootTable = JSON.toJavaObject(JSON.parseObject(destTask.getConfig()), Config.class).getRootTables().get(destTableName);
        String destTableNameInDb = PostgreSqlUtil.buildTableNameString(destTask.getDatabaseName(), destTableName, false, false);
        Map<String,Field> destFields = destRootTable.getFields();
        List<String> srcTableFieldOrder = new ArrayList<>();
        List<String> destTableFieldOrder = new ArrayList <>();
        genTableFieldOrder(fieldMapping, srcTableFieldOrder, destTableFieldOrder, TableOperationUtil.getPrimaryKey(destRootTable));
        Long dataCount = 0L;
        Integer collectorId = -1;
        if (CollectionUtils.isNotEmpty(srcRootTableList))
        {
            for (Map<String,Object> srcRootTableData : srcRootTableList)
            {
                // 用于Field的控件类型为Photo的oldFilePath和newFilePath,待数据插入成功后在复制多媒体文件
                Map<String,String> srcAndDestPhotoPathMap = new HashMap <>();
                StringBuilder insertSb = new StringBuilder(" INSERT INTO ").append(destTableNameInDb).append("(");
                StringBuilder valueSb = new StringBuilder(" VALUES (");
                insertSb.append(CommonConstant.FIX_FIELD_CREATE_TIME).append(",").append(CommonConstant.FIX_FIELD_UPDATE_TIME).append(",")
                        .append(CommonConstant.FIX_FIELD_STATUS).append(",").append(CommonConstant.FIX_FIELD_VERSION).append(",")
                        .append(CommonConstant.FIX_FIELD_COLLECTOR).append(",").append(CommonConstant.FIX_FIELD_REVIEWER).append(",");
                valueSb.append(GenerateSqlUtil.generatePostgreSqlDateValue(new Date(), null)).append(",")
                        .append(GenerateSqlUtil.generatePostgreSqlDateValue(new Date(), null)).append(",")
                        .append(0).append(",").append(0).append(",").append(collectorId).append(",").append(-1).append(",");
                for (String destTableFieldName : destTableFieldOrder)
                {
                    String srcTableFieldName = srcTableFieldOrder.get(destTableFieldOrder.indexOf(destTableFieldName));
                    if (!srcRootTableData.keySet().contains(srcTableFieldName))
                    {
                        continue;
                    }
                    insertSb.append(PostgreSqlUtil.transformString(destTableFieldName)).append(",");
                    Field field = destFields.get(destTableFieldName);
                    if (field.getAutoDate() != null && !field.getAutoDate().equals("") && field.getDbType().equals(CommonConstant.DATE))
                    {
                        valueSb.append(GenerateSqlUtil.generatePostgreSqlDateValue(srcRootTableData.get(srcTableFieldName).toString(), CommonConstant.DATE_FORMAT_STRING)).append(",");
                        continue;
                    }
                    // 针对于Field的控件类型是PHOTO的情况处理
                    if (StringUtils.isNotBlank(field.getType()) && field.getType().toLowerCase().equals(CommonConstant.PHOTO))
                    {
                        String srcPhotoPath = srcRootTableData.get(srcTableFieldName).toString();
                        String srcTaskIdString = "task_" + srcTask.getId();
                        String destTaskIdString = "task_" + destTask.getId();
                        String destPhotoPath = srcPhotoPath.replace(srcTaskIdString,destTaskIdString);
                        String destUserIdString = "/user_" + collectorId;
                        String subDestPhotoPath = destPhotoPath.substring(0, destPhotoPath.lastIndexOf("/"));
                        String trueDestPhotoPath = subDestPhotoPath.substring(0,subDestPhotoPath.lastIndexOf("/")) + destUserIdString + destPhotoPath.substring(destPhotoPath.lastIndexOf("/"), destPhotoPath.length());
                        valueSb.append("\'").append(trueDestPhotoPath).append("\',");
                        srcAndDestPhotoPathMap.put(srcPhotoPath,trueDestPhotoPath);
                        continue;
                    }
                    valueSb = GenerateSqlUtil.appendValueForDifferentField(valueSb, srcRootTableData.get(srcTableFieldName),
                                                                           field.getDbType().toLowerCase(), null);
                }
                dataCount += 1;
//                if (dataCount % 100 == 0)
//                {
//                    collectorId -= 1;
//                }
                String insertSql = insertSb.substring(0 , insertSb.length() - 1) + ") " + valueSb.substring(0 , valueSb.length() - 1) + ");";
                Long destPolygonId;
                SqlEnity sqlEnity = new SqlEnity();
                sqlEnity.setSql(insertSql);
                String primaryKeySeq = GenerateSqlUtil.generatePrimaryKeySeq(destTask.getDatabaseName(), destRootTable);
                sqlEnity.setPrimaryKeySeq(primaryKeySeq);
                destPolygonId = baseService.insertSqlEnity(sqlEnity);
                if (destPolygonId == null || destPolygonId == 0)
                {
                    throw new RuntimeException("数据插入失败");
                }
                // 数据插入成功后，将srcAndDestPhotoPathMap中照片迁移
                photoPathMapMigration(srcAndDestPhotoPathMap);

                // 插入源表的多媒体信息
                String srcMeidaTableName = PostgreSqlUtil.buildTableNameString(srcTask.getDatabaseName(), srcTableName,true,false);
                Long srcPolygonId = Long.valueOf(srcRootTableData.get(TableOperationUtil.getPrimaryKey(srcRootTable)).toString());
                List<MultimediaItem> multimediaItemList = multimediaService.selectMultiMedia(srcMeidaTableName, srcPolygonId);
                if (CollectionUtils.isNotEmpty(multimediaItemList))
                {
                    for (MultimediaItem multimediaItem : multimediaItemList)
                    {
                        String srcMediaPath = multimediaItem.getMediaPath();
                        String srcTaskIdString = "task_" + srcTask.getId();
                        String destTaskIdString = "task_" + destTask.getId();
                        String destMediaPath = srcMediaPath.replace(srcTaskIdString,destTaskIdString);
                        String destUserIdString = "/user_" + collectorId;
                        String subDestMediaPath = destMediaPath.substring(0, destMediaPath.lastIndexOf("/"));
                        String trueDestMediaPath = subDestMediaPath.substring(0,subDestMediaPath.lastIndexOf("/")) + destUserIdString + destMediaPath.substring(destMediaPath.lastIndexOf("/"), destMediaPath.length());
                        multimediaItem.setMediaPath(trueDestMediaPath);
                        multimediaItem.setID(destPolygonId);
                        multimediaItem.setVersion(0);
                        multimediaItem.setMediaTableName(PostgreSqlUtil.buildTableNameString(destTask.getDatabaseName(), destTableName, true, false));
                        String insertMediaResult = multimediaService.insertMultiMedia(multimediaItem);
                        if (insertMediaResult.equals(CommonConstant.FAILED))
                        {
                            throw new RuntimeException("插入多媒体数据失败");
                        }
                        // 在多媒体数据都插入成功的情况下，进行多媒体文件迁移
                        FileUtils.copyFile(new File(CommonConstant.MEDIA_ROOT + srcMediaPath), new File(CommonConstant.MEDIA_ROOT + trueDestMediaPath));
                    }
                }
            }
        }

        // 当 srcRootTableList不为空，将本次抽查的数据主键存入 task_select_id 表中
        if (CollectionUtils.isNotEmpty(srcRootTableList)){
            Integer maxSelectOrder = taskSelectIdService.getMaxSelectOrder(srcTaskId, srcTableName,
                                                                           destTaskId, destTableName);
            TaskSelectId taskSelectId = new TaskSelectId();
            taskSelectId.setSrcTaskId(srcTaskId);
            taskSelectId.setSrcTableName(srcTableName);
            taskSelectId.setDestTaskId(destTaskId);
            taskSelectId.setDestTableName(destTableName);
            taskSelectId.setSelectOrder(maxSelectOrder == null ? 1 : maxSelectOrder + 1);
            StringBuilder selectIdSb = new StringBuilder();
            srcRootTableList.forEach(srcRootTableData -> selectIdSb.append(srcRootTableData.get(srcPrimaryKey).toString())
                                    .append(","));
            taskSelectId.setSelectId(selectIdSb.substring(0, selectIdSb.length() - 1));
            if (taskSelectIdService.insertTaskSelectId(taskSelectId).equals(CommonConstant.FAILED))
            {
                throw new RuntimeException("TaskSelectId数据插入失败");
            }
        }
        return new ResultMessage(true, CommonConstant.SUCCEED);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void fileDataInsert (Task destTask, String destTableName, Sheet sheet, String fieldMapping) throws IOException
    {
        Table destRootTable = JSON.toJavaObject(JSON.parseObject(destTask.getConfig()), Config.class).getRootTables().get(destTableName);
        Map<String,Field> destFields = destRootTable.getFields();
        List<String> srcTableFieldOrder = new ArrayList<>();
        List<String> destTableFieldOrder = new ArrayList <>();
        String primaryKey = TableOperationUtil.getPrimaryKey(destRootTable);
        genTableFieldOrder(fieldMapping, srcTableFieldOrder, destTableFieldOrder, primaryKey);
        String destTableNameInDB = PostgreSqlUtil.buildTableNameString(destTask.getDatabaseName(), destTableName, false, false);

        // 用于记录数据的个数，collectorId是为了与正常采集逻辑保持一致
        Long dataCount = 0L;
        Integer collectorId = -1;
        // 遍历Sheet中数据
        Row firstRow = sheet.getRow(sheet.getFirstRowNum());
        for (int i = sheet.getFirstRowNum() + 1; i <= sheet.getLastRowNum(); i++)
        {
            // 用于Field的控件类型为Photo的oldFilePath和newFilePath,待数据插入成功后在复制多媒体文件
            Map<String,String> srcAndDestPhotoPathMap = new HashMap <>();
            StringBuilder insertSb = new StringBuilder(" INSERT INTO ").append(destTableNameInDB).append("(");
            StringBuilder valueSb = new StringBuilder(" VALUES (");
            insertSb.append(CommonConstant.FIX_FIELD_CREATE_TIME).append(",").append(CommonConstant.FIX_FIELD_UPDATE_TIME).append(",")
                    .append(CommonConstant.FIX_FIELD_STATUS).append(",").append(CommonConstant.FIX_FIELD_VERSION).append(",")
                    .append(CommonConstant.FIX_FIELD_COLLECTOR).append(",");
            valueSb.append(GenerateSqlUtil.generatePostgreSqlDateValue(new Date(), null)).append(",")
                    .append(GenerateSqlUtil.generatePostgreSqlDateValue(new Date(), null)).append(",")
                    .append(0).append(",").append(0).append(",").append(collectorId).append(",");
            for (String destTableFieldName : destTableFieldOrder)
            {
                String srcTableFieldName = srcTableFieldOrder.get(destTableFieldOrder.indexOf(destTableFieldName));
                int cellIndex = getCellIndex(firstRow, srcTableFieldName);
                assert cellIndex != -1;
                if (sheet.getRow(i).getCell(cellIndex) == null)
                {
                    continue;
                }
                Field field = destFields.get(destTableFieldName);
                Cell cell = sheet.getRow(i).getCell(cellIndex);
                String cellValue;
                if (cell.getCellType().name().equals("NUMERIC"))
                {
                    DecimalFormat df = new DecimalFormat("0");
                    cellValue = df.format(cell.getNumericCellValue());
                }
                else
                {
                    cellValue = cell.toString();
                }
                insertSb.append(PostgreSqlUtil.transformString(destTableFieldName)).append(",");
                if (field.getAutoDate() != null && !field.getAutoDate().equals("") && field.getDbType().equals(CommonConstant.DATE))
                {
                    valueSb.append(GenerateSqlUtil.generatePostgreSqlDateValue(cellValue, CommonConstant.DATE_FORMAT_STRING)).append(",");
                    continue;
                }
                // 针对于Field的控件类型是PHOTO的情况处理
                if (StringUtils.isNotBlank(field.getType()) && field.getType().toLowerCase().equals(CommonConstant.PHOTO))
                {
                    String srcPhotoFileName = cellValue.substring(cellValue.lastIndexOf("/") + 1, cellValue.length());
                    String destPhotoPath = MessageFormat.format(CommonConstant.MEDIA_FILE_PATHNAME, destTask.getId(),
                                                                collectorId, srcPhotoFileName);
                    valueSb.append("\'").append(destPhotoPath).append("\',");
                    srcAndDestPhotoPathMap.put(cellValue,destPhotoPath);
                    continue;
                }
                valueSb = GenerateSqlUtil.appendValueForDifferentField(valueSb, cellValue, field.getDbType().toLowerCase(), null);
            }
            dataCount += 1;
//            if (dataCount % 100 == 0)
//            {
//                collectorId -= 1;
//            }
            // 判断fieldMapping中是否有主键字段
            Long destPolygonId = 0L;
            if (fieldMappingContainPrimaryKey(fieldMapping, primaryKey))
            {
                insertSb.append(PostgreSqlUtil.transformString(primaryKey)).append(",");
                String srcPrimaryKeyFieldName = getSrcFieldNameByDestFieldName(fieldMapping, primaryKey);
                int cellIndex = getCellIndex(firstRow, srcPrimaryKeyFieldName);
                assert cellIndex != -1;
                if (sheet.getRow(i).getCell(cellIndex) == null)
                {
                    throw new RuntimeException("数据缺少主键值");
                }
                Field field = destFields.get(primaryKey);
                Cell cell = sheet.getRow(i).getCell(cellIndex);
                String cellValue;
                if (cell.getCellType().name().equals("NUMERIC"))
                {
                    DecimalFormat df = new DecimalFormat("0");
                    cellValue = df.format(cell.getNumericCellValue());
                }
                else
                {
                    cellValue = cell.toString();
                }
                destPolygonId = Long.parseLong(cellValue);
                valueSb = GenerateSqlUtil.appendValueForDifferentField(valueSb, cellValue, field.getDbType().toLowerCase(), null);
                String insertSql = insertSb.substring(0 , insertSb.length() - 1) + ") " + valueSb.substring(0 , valueSb.length() - 1) + ");";
                String insertResult= baseService.insertSqlString(insertSql);
                if (insertResult.equals(CommonConstant.FAILED))
                {
                    throw new RuntimeException("数据插入失败");
                }
                // 数据插入成功后，将srcAndDestPhotoPathMap中照片迁移
                photoPathMapMigration(srcAndDestPhotoPathMap);
            }
            else
            {
                String insertSql = insertSb.substring(0 , insertSb.length() - 1) + ") " + valueSb.substring(0 , valueSb.length() - 1) + ");";
                SqlEnity sqlEnity = new SqlEnity();
                sqlEnity.setSql(insertSql);
                String primaryKeySeq = GenerateSqlUtil.generatePrimaryKeySeq(destTask.getDatabaseName(), destRootTable);
                sqlEnity.setPrimaryKeySeq(primaryKeySeq);
                destPolygonId = baseService.insertSqlEnity(sqlEnity);
                if (destPolygonId == null || destPolygonId == 0)
                {
                    throw new RuntimeException("插入失败");
                }
                photoPathMapMigration(srcAndDestPhotoPathMap);
            }
            // 判断firstRow的最后一列值是否为filePath，如果是则有多媒体文件，插入多媒体信息
            if (firstRow.getCell(firstRow.getLastCellNum() - 1).toString().toLowerCase().equals(CommonConstant.FILE_PATH))
            {
                insertMultiMedia(sheet.getRow(i).getCell(sheet.getRow(i).getLastCellNum() -1).toString(), destTask,
                                 collectorId, destPolygonId, destTableName);
            }
        }

        String seqName = genSeqName(destTask.getDatabaseName(),destTableName , primaryKey);
        Integer maxId = updateMapper.getMaxId(PostgreSqlUtil.transformString(primaryKey), destTableNameInDB);
        updateMapper.updatePrimaryKey(seqName, maxId == null ? 1 : maxId + 1);
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void shpDataInsert (Task destTask, String destTableName, SimpleFeatureIterator itertor, String fieldMapping,
                               String mediaFilePath) throws IOException, ParseException, InvalidShapefileException {
        Table destRootTable = JSON.toJavaObject(JSON.parseObject(destTask.getConfig()), Config.class).getRootTables().get(destTableName);
        Map<String,Field> destFields = destRootTable.getFields();
        List<String> srcTableFieldOrder = new ArrayList<>();
        List<String> destTableFieldOrder = new ArrayList <>();
        String primaryKey = TableOperationUtil.getPrimaryKey(destRootTable);
        genTableFieldOrder(fieldMapping, srcTableFieldOrder, destTableFieldOrder, primaryKey);
        String destTableNameInDB = PostgreSqlUtil.buildTableNameString(destTask.getDatabaseName(), destTableName, false, false);

        // 用于记录数据的个数，collectorId是为了与正常采集逻辑保持一致
        Long dataCount = 0L;
        Integer collectorId = -1;
        // 遍历SimpleFeatureIterator
        while (itertor.hasNext())
        {
            // 用于Field的控件类型为Photo的oldFilePath和newFilePath,待数据插入成功后在复制多媒体文件
            Map<String,String> srcAndDestPhotoPathMap = new HashMap <>();
            StringBuilder insertSb = new StringBuilder(" INSERT INTO ").append(destTableNameInDB).append("(");
            StringBuilder valueSb = new StringBuilder(" VALUES (");
            insertSb.append(CommonConstant.FIX_FIELD_CREATE_TIME).append(",").append(CommonConstant.FIX_FIELD_UPDATE_TIME).append(",")
                    .append(CommonConstant.FIX_FIELD_STATUS).append(",").append(CommonConstant.FIX_FIELD_VERSION).append(",")
                    .append(CommonConstant.FIX_FIELD_COLLECTOR).append(",").append(CommonConstant.FIX_FIELD_REVIEWER).append(",");
            valueSb.append(GenerateSqlUtil.generatePostgreSqlDateValue(new Date(), null)).append(",")
                    .append(GenerateSqlUtil.generatePostgreSqlDateValue(new Date(), null)).append(",")
                    .append(0).append(",").append(0).append(",").append(collectorId).append(",").append(-1).append(",");
            // 获取每个SimpleFeature的Collection<Property>
            SimpleFeature feature = itertor.next();
            Collection<Property> properties = feature.getProperties();
            for (String destTableFieldName : destTableFieldOrder)
            {
                String srcTableFieldName = srcTableFieldOrder.get(destTableFieldOrder.indexOf(destTableFieldName));
                Object value = getValueByFieldName(properties, srcTableFieldName);
                if (value == null)
                {
                    continue;
                }
                Field field = destFields.get(destTableFieldName);
                insertSb.append(PostgreSqlUtil.transformString(destTableFieldName)).append(",");
                if (field.getAutoDate() != null && !field.getAutoDate().equals("") && field.getDbType().equals(CommonConstant.DATE))
                {
                    valueSb.append(GenerateSqlUtil.generatePostgreSqlDateValue(value, CommonConstant.DATE_FORMAT_STRING)).append(",");
                    continue;
                }
                // 针对于Field的控件类型是PHOTO的情况处理
                if (StringUtils.isNotBlank(field.getType()) && field.getType().toLowerCase().equals(CommonConstant.PHOTO))
                {
                    String valueString = value.toString();
                    String srcPhotoFileName = valueString.substring(valueString.lastIndexOf("/") + 1, valueString.length());
                    String destPhotoPath = MessageFormat.format(CommonConstant.MEDIA_FILE_PATHNAME, destTask.getId(),
                                                                collectorId, srcPhotoFileName);
                    valueSb.append("\'").append(destPhotoPath).append("\',");
                    srcAndDestPhotoPathMap.put(valueString,destPhotoPath);
                    continue;
                }
                // 针对Geometry字段需要特殊处理
                if (field.isGeometry())
                {
//                    valueSb.append("\'").append(changeShpGeomToGeometry(value.toString())).append("\',");
//                    continue;
//                    Geometry geometry = (Geometry) value;
//                    GeometryJSON geometryJson = new GeometryJSON(15); // 保留高精度
//                    StringWriter writer = new StringWriter();
//                    geometryJson.write(geometry, writer);  // 保留完整结构（含 holes / multipolygon）
//                    String geoJsonString = writer.toString();
//                    valueSb.append("'").append(geoJsonString.replace("'", "''")).append("',");  // 注意 SQL 转义
//                    continue;
                    Geometry geometry = (Geometry) value;
                    GeometryJSON geometryJson = new GeometryJSON(15); // 保留高精度
                    StringWriter writer = new StringWriter();
                    geometryJson.write(geometry, writer);
                    String geoJsonString = writer.toString();

                 // 反序列化为自定义 GeometryType
                    GeometryType geometryType = JSON.toJavaObject(
                            JSON.parseObject(geoJsonString),
                            GeometryType.class
                    );

                // 如果是 MultiPolygon，就降级为 Polygon，只保留第一组坐标
                    if (geometryType.getType().equalsIgnoreCase(CommonConstant.MULTIPOLYGON)) {
                        geometryType.setType(CommonConstant.POLYGON);

                        @SuppressWarnings("unchecked")
                        List<List<List<List<Object>>>> coordList =
                                (List<List<List<List<Object>>>>) geometryType.getCoordinates();
                        // 只取第一组 polygon 的坐标
                        geometryType.setCoordinates(coordList.get(0));
                    }

                   // 转回 JSON 字符串，用于存库
                    String finalGeoJson = JSON.toJSONString(geometryType);
                    valueSb.append("'").append(finalGeoJson.replace("'", "''")).append("',");
                    continue;
                }
                valueSb = GenerateSqlUtil.appendValueForDifferentField(valueSb, value, field.getDbType().toLowerCase(), null);
            }
            dataCount += 1;
//            if (dataCount % 100 == 0)
//            {
//                collectorId -= 1;
//            }
            // 判断fieldMapping中是否有主键字段
            Long destPolygonId = 0L;
            if (fieldMappingContainPrimaryKey(fieldMapping, primaryKey)){
                insertSb.append(PostgreSqlUtil.transformString(primaryKey)).append(",");
                String srcPrimaryKeyFieldName = getSrcFieldNameByDestFieldName(fieldMapping, primaryKey);
                Object value = getValueByFieldName(properties, srcPrimaryKeyFieldName);
                if (value == null)
                {
                    throw new InvalidShapefileException("数据缺少主键值");
                }
                destPolygonId = Long.parseLong(value.toString());
                if (destPolygonId == 0) {
                    throw new InvalidShapefileException("主键不能为0");
                }
                Field field = destFields.get(primaryKey);
                valueSb = GenerateSqlUtil.appendValueForDifferentField(valueSb, value, field.getDbType().toLowerCase(), null);
                String insertSql = insertSb.substring(0 , insertSb.length() - 1) + ") " + valueSb.substring(0 , valueSb.length() - 1) + ");";
                String insertResult= baseService.insertSqlString(insertSql);
                if (insertResult.equals(CommonConstant.FAILED))
                {
                    throw new RuntimeException("数据插入失败");
                }
                // 数据插入成功后，将srcAndDestPhotoPathMap中照片迁移
                photoPathMapMigration(srcAndDestPhotoPathMap);
            }
            else
            {
                String insertSql = insertSb.substring(0 , insertSb.length() - 1) + ") " + valueSb.substring(0 , valueSb.length() - 1) + ");";
                SqlEnity sqlEnity = new SqlEnity();
                sqlEnity.setSql(insertSql);
                String primaryKeySeq = GenerateSqlUtil.generatePrimaryKeySeq(destTask.getDatabaseName(), destRootTable);
                sqlEnity.setPrimaryKeySeq(primaryKeySeq);
                destPolygonId = baseService.insertSqlEnity(sqlEnity);
                if (destPolygonId == null || destPolygonId == 0)
                {
                    throw new RuntimeException("数据插入失败");
                }
                // 数据插入成功后，将srcAndDestPhotoPathMap中照片迁移
                photoPathMapMigration(srcAndDestPhotoPathMap);
            }
            // 判断firstRow的最后一列值是否为filePath，如果是则有多媒体文件，插入多媒体信息
            if (mediaFilePath != null)
            {
                // 另外插入多媒体信息
                if (getValueByFieldName(properties, mediaFilePath) != null)
                {
                    insertMultiMedia(getValueByFieldName(properties, mediaFilePath).toString(), destTask, collectorId,
                                     destPolygonId, destTableName);
                }
            }
        }

        String seqName = genSeqName(destTask.getDatabaseName(),destTableName , primaryKey);
        Integer maxId = updateMapper.getMaxId(PostgreSqlUtil.transformString(primaryKey), destTableNameInDB);
        updateMapper.updatePrimaryKey(seqName, maxId == null ? 1 : maxId + 1);
    }

    /**
     * 向srcTableFieldOrder，destTableFieldOrder添加TableName.注意这里的List中不包括主键字段名
     */
    private void genTableFieldOrder(String fieldMapping, List<String> srcTableFieldOrder, List<String> destTableFieldOrder, String primaryKey)
    {
        JSONArray jsonArray = JSON.parseArray(fieldMapping);
        for (Object object : jsonArray)
        {
            JSONObject jsonObject = (JSONObject) object;
            if (!jsonObject.getString("destTableField").equals(primaryKey))
            {
                destTableFieldOrder.add(jsonObject.getString("destTableField"));
                srcTableFieldOrder.add(jsonObject.getString("srcTableField"));
            }
        }
    }

    /**
     * 检查前端传来的fieldMapping，是否有destTableField为主键，如果有主键，根据Excel或shp中主键列插值；
     * 没有主键，则按照主键自增插值
     */
    private boolean fieldMappingContainPrimaryKey(String fieldMapping, String primaryKey)
    {
        JSONArray jsonArray = JSON.parseArray(fieldMapping);
        for (Object object : jsonArray)
        {
            JSONObject jsonObject = (JSONObject) object;
            if (jsonObject.getString("destTableField").equals(primaryKey))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 基于fieldMapping，根据destFieldName找到对应的srcFieldName
     */
    private String getSrcFieldNameByDestFieldName(String fieldMapping, String destFieldName)
    {
        JSONArray jsonArray = JSON.parseArray(fieldMapping);
        for (Object object : jsonArray)
        {
            JSONObject jsonObject = (JSONObject) object;
            if (jsonObject.getString("destTableField").equals(destFieldName))
            {
                return jsonObject.getString("srcTableField");
            }
        }
        return null;
    }

    /**
     * 获取Sheet的cellName所在的cellIndex
     */
    private int getCellIndex(Row fisrtRow, String cellName)
    {
        for (int i = 0; i < fisrtRow.getLastCellNum(); i++)
        {
            if (fisrtRow.getCell(i).toString().equals(cellName))
            {
                return i;
            }
        }
        return -1;
    }

    /**
     * 在数据插入成功后，将srcAndDestPhotoPathMap中照片迁移
     */
    private void photoPathMapMigration(Map<String,String> srcAndDestPhotoPathMap)
    {
        if (MapUtils.isNotEmpty(srcAndDestPhotoPathMap))
        {
            srcAndDestPhotoPathMap.forEach((srcPath,destPath)-> {
                try
                {
                    FileUtils.copyFile(new File(srcPath), new File(destPath));
                }
                catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }});
        }
    }

    /**
     * 从Collection<Property>中根据属性值
     */
    private Object getValueByFieldName(Collection<Property> properties, String fieldName)
    {
        //遍历feature的properties
        for (Property pro : properties)
        {
            if (pro.getName().toString().equals(fieldName))
            {
                return pro.getValue();
            }
        }
        return null;
    }

    /**
     * 根据传进来的mediaFilePath字符串（可能存在多个路径，用逗号隔开），进行MultiMedia插入
     */
    private void insertMultiMedia(String mediaFilePath, Task task, Integer collectorId, Long destPolygonId,
                                  String destTableName) throws IOException
    {
        if (StringUtils.isNotBlank(mediaFilePath))
        {
            String[] filePathStringArr = mediaFilePath.split(",");
            for (String filePath : filePathStringArr)
            {
                String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length());
                String destMediaPath = MessageFormat.format(CommonConstant.MEDIA_FILE_PATHNAME, task.getId(), collectorId, fileName);
                MultimediaItem multimediaItem = new MultimediaItem();
                multimediaItem.setID(destPolygonId);
                multimediaItem.setFile(fileName);
                multimediaItem.setMediaPath(destMediaPath);
                multimediaItem.setVersion(0);
                multimediaItem.setMediaTableName(PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), destTableName, true, false));
                String insertMediaResult = multimediaService.insertMultiMedia(multimediaItem);
                if (insertMediaResult.equals(CommonConstant.FAILED))
                {
                    throw new RuntimeException("数据多媒体失败");
                }
                // 在多媒体数据都插入成功的情况下，进行多媒体文件迁移
                FileUtils.copyFile(new File(filePath), new File(destMediaPath));
            }
        }
    }

    /**
     * 将WKT字符串格式转为Geometry格式
     */
//    private String changeShpGeomToGeometry(String geomString) throws ParseException, IOException
//    {
//        WKTReader wktReader = new WKTReader();
//        Geometry geometry = wktReader.read(geomString);
//        GeometryJSON geometryJson = new GeometryJSON(15);
//        StringWriter writer = new StringWriter();
//        geometryJson.write(geometry, writer);
//        GeometryType geometryType = JSON.toJavaObject(JSON.parseObject(writer.toString()), GeometryType.class);
//        if (geometryType.getType().toLowerCase().equals(CommonConstant.MULTIPOLYGON.toLowerCase()))
//        {
//            geometryType.setType(CommonConstant.POLYGON);
//            List<List<List<List<Object>>>> coordList = (List<List<List<List<Object>>>>)geometryType.getCoordinates();
//            geometryType.setCoordinates(coordList.get(0));
//        }
//        return JSON.toJSONString(geometryType);
//    }

    /**
     * 从taskSelectIdList获取selectId的List<Integer>
     */
    private List<Integer> getSelectIdList(List<TaskSelectId> taskSelectIdList){
        List<Integer> result = new ArrayList <>();
        taskSelectIdList.forEach(taskSelectId -> {
            String[] selectIdArr = taskSelectId.getSelectId().split(",");
            result.addAll(Arrays.stream(selectIdArr).map(Integer::valueOf).collect(Collectors.toList()));
        });
        return result;
    }

    public String genSeqName(String databaseName, String tableName, String primaryKey){
        return PostgreSqlUtil.transformString(databaseName) + "." + PostgreSqlUtil.transformString(tableName + "_" + primaryKey + "_seq");
    }
}
