package cn.edu.whu.boot.collection.controller;

import cn.edu.whu.boot.allocation.services.TaskUserRoleService;
import cn.edu.whu.boot.collection.domain.MultimediaItem;
import cn.edu.whu.boot.collection.domain.TaskSelectId;
import cn.edu.whu.boot.collection.dto.Feature;
import cn.edu.whu.boot.collection.dto.GeometryType;
import cn.edu.whu.boot.collection.service.IBaseService;
import cn.edu.whu.boot.collection.service.IMultimediaService;
import cn.edu.whu.boot.collection.service.ISearchPageService;
import cn.edu.whu.boot.collection.service.ITaskSelectIdService;
import cn.edu.whu.boot.common.domain.CommonConstant;
import cn.edu.whu.boot.common.domain.ResultMessage;
import cn.edu.whu.boot.common.domain.SqlStringConstant;
import cn.edu.whu.boot.common.utils.collection.*;
import cn.edu.whu.boot.common.utils.xml.CheckTableDataUtil;
import cn.edu.whu.boot.common.utils.xml.GenerateSqlUtil;
import cn.edu.whu.boot.user.entities.Role;
import cn.edu.whu.boot.user.entities.User;
import cn.edu.whu.boot.user.services.RoleService;
import cn.edu.whu.boot.user.services.UserService;
import cn.edu.whu.boot.xml.domain.Task;
import cn.edu.whu.boot.xml.service.ITaskService;
import cn.edu.whu.boot.xml.service.IXmlEnityService;
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.serializer.SerializerFeature;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 这个类也比较混乱，按道理这个类是想放一些获取相关的接口，奈何后面获取内容太多，导致方法太多。
 * 具体接口的含义参考注释
 */
@RestController
@RequestMapping("get")
public class GetController {

    private static final Logger log = LoggerFactory.getLogger(GetController.class);
    private final ITaskService taskService;
    private final IBaseService baseService;
    private final IMultimediaService multimediaService;
    private final UserService userService;
    private final IXmlEnityService xmlEnityService;
    private final ISearchPageService searchPageService;
    private final ITaskSelectIdService taskSelectIdService;
    private final TaskUserRoleService taskUserRoleService;
    /**
     * 多媒体存放路径
     */
    @Value("${MediaPath}")
    private String mediaPath;

    /**
     * 历史多媒体存放路径
     */
    @Value("${HistoryMediaPath}")
    private String historyMediaPath;

    @Autowired
    public GetController(ITaskService taskService, IBaseService baseService, IMultimediaService multimediaService,
                         UserService userService, IXmlEnityService xmlEnityService, ISearchPageService searchPageService,
                         ITaskSelectIdService taskSelectIdService, TaskUserRoleService taskUserRoleService, RoleService roleservice){
        this.taskService = taskService;
        this.baseService = baseService;
        this.multimediaService = multimediaService;
        this.userService = userService;
        this.xmlEnityService = xmlEnityService;
        this.searchPageService = searchPageService;
        this.taskSelectIdService = taskSelectIdService;
        this.taskUserRoleService = taskUserRoleService;
    }

    /**
     * 获取图片，图片直接在浏览器端显示，而不是显示下载框
     * 采用 @PathVariable 注解将参数设置在 URL 中
     * @param  taskId        任务id
     * @param  userId        用户id
     * @param  pictureName   图片名
     *
     */
    @RequestMapping(value = "getPicture/{taskId}/{userId}/{pictureName}", produces = "text/html;charset=UTF-8")
    public String getPicture(@PathVariable("taskId") Integer taskId, @PathVariable("userId") Integer userId,
                             @PathVariable("pictureName") String pictureName, HttpServletResponse response){
        String format = pictureName.substring(pictureName.lastIndexOf(".") + 1, pictureName.length());
        response.setContentType("image/" + format);
        String fileName = MessageFormat.format(CommonConstant.MEDIA_FILE_PATHNAME,  taskId, userId, pictureName);
        File file = new File(fileName);
        if(!file.exists()){
            fileName = MessageFormat.format(CommonConstant.HISTORY_MEDIA_FILE_PATHNAME, taskId, userId, pictureName);
            file = new File(fileName);
            if (!file.exists()){
                return ResultMessage.failed( "图片不存在").toString();
            }
        }
        String result = OtherUtil.uploadFileByResponse(file, response);
        if(result.equals(CommonConstant.SUCCEED)){
            return ResultMessage.success(CommonConstant.SUCCEED).toString();
        }
        else{
            return ResultMessage.failed(CommonConstant.FAILED).toString();
        }
    }
//    @RequestMapping(value = "getPicture/{taskId}/{userId}/{pictureName}", produces = "text/html;charset=UTF-8")
//    public String getPicture(@PathVariable("taskId") Integer taskId,
//                             @PathVariable("userId") String userId,
//                             @PathVariable("pictureName") String pictureName,
//                             HttpServletResponse response) {
//        String format = pictureName.substring(pictureName.lastIndexOf(".") + 1);
//        response.setContentType("image/" + format);
//        File file;
//
//        if ("unknown".equals(userId)) {
//            // 在 mediafile/task_{taskId}/user_* 中遍历查找图片
//            String taskFolderPath = MessageFormat.format(CommonConstant.MEDIA_TASK_FOLDER_PATH , taskId); // eg: "mediafile/task_{0}"
//            File taskFolder = new File(taskFolderPath);
//            file = null;
//            if (taskFolder.exists() && taskFolder.isDirectory()) {
//                File[] userFolders = taskFolder.listFiles(File::isDirectory);
//                if (userFolders != null) {
//                    for (File userFolder : userFolders) {
//                        File potentialFile = new File(userFolder, pictureName);
//                        if (potentialFile.exists()) {
//                            file = potentialFile;
//                            break;
//                        }
//                    }
//                }
//            }
//        } else {
//            // 构造标准路径
//            String filePath = MessageFormat.format(CommonConstant.MEDIA_FILE_PATHNAME, taskId, userId, pictureName);
//            file = new File(filePath);
//
//            // 查找历史路径
//            if (!file.exists()) {
//                filePath = MessageFormat.format(CommonConstant.HISTORY_MEDIA_FILE_PATHNAME, taskId, userId, pictureName);
//                file = new File(filePath);
//            }
//        }
//
//        if (file == null || !file.exists()) {
//            return ResultMessage.failed("图片不存在").toString();
//        }
//
//        String result = OtherUtil.uploadFileByResponse(file, response);
//        if (CommonConstant.SUCCEED.equals(result)) {
//            return ResultMessage.success(CommonConstant.SUCCEED).toString();
//        } else {
//            return ResultMessage.failed(CommonConstant.FAILED).toString();
//        }
//    }

    /**
     * 获取视频，固定视频格式 .avi，该获取是浏览器获取视频二进制流，且直接播放而不是提示下载
     * 如若下载添加 response.addHeader("Content-Disposition", "attachment;fileName=自设置文件名");
     * @param  taskId        任务id
     * @param  userId        用户id
     * @param  videoName     视频名
     */
    @RequestMapping(value = "getVideo/{taskId}/{userId}/{videoName}", produces = "text/html;charset=UTF-8")
    public String getVideo(@PathVariable("taskId") Integer taskId, @PathVariable("userId") Integer userId,
                           @PathVariable("videoName") String videoName, HttpServletResponse response){
        response.setContentType("video/mp4");
        String fileName = MessageFormat.format(CommonConstant.MEDIA_FILE_PATHNAME, taskId, userId, videoName);
        File file = new File(fileName);
        if(!file.exists()){
            fileName = MessageFormat.format(CommonConstant.HISTORY_MEDIA_FILE_PATHNAME, taskId, userId, videoName);
            file = new File(fileName);
            if (!file.exists()){
                return ResultMessage.failed("视频文件不存在").toString();
            }
        }
        String result = OtherUtil.uploadFileByResponse(file, response);
        if(result.equals(CommonConstant.SUCCEED)){
            return ResultMessage.success(CommonConstant.SUCCEED).toString();
        }
        else{
            return ResultMessage.failed(CommonConstant.FAILED).toString();
        }
    }

    /**
     * 根据根表中的主键字段查询多媒体文件，并通过 HttpServletResponse 提供下载
     * @param  taskId        任务id
     * @param  tableName     表名
     * @param  polygonId     数据主键id
     */
    @RequestMapping(value="getMediaFile",produces="text/html;charset=UTF-8")
    public String selectMediaFileById(Integer taskId, String tableName, Long polygonId, HttpServletResponse response){
        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class).getTables().get(tableName);
//        String mediaTableName = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, true, false);
//        List<MultimediaItem> multimediaItemList = multimediaService.selectMultiMedia(mediaTableName, polygonId);
//        String selectByPolygonIdSql = GenerateSqlUtil.generateSelectSqlByField(task.getDatabaseName(), tableName,
//                                                                               TableOperationUtil.getPrimaryKey(table),
//                                                                               polygonId);
//        List<Map<String, Object>> rootTableDataList = baseService.selectData(selectByPolygonIdSql);
//        if (rootTableDataList == null || rootTableDataList.isEmpty()){
//            return ResultMessage.failed( "无该主键对应记录").toString();
//        }
//        Map<String, Object> rootTableData = rootTableDataList.get(0);
//        // 检查下表中是否有表字段的 type 是 photo，若有，将该字段值对应的路径存放在 mediaFileNameList 中
//        List<String> mediaFileNameList = new ArrayList<>();
//        for (Map.Entry<String,Field> fieldEntry : table.getFields().entrySet()){
//            if (fieldEntry.getValue().getType() != null && fieldEntry.getValue().getType().equals(CommonConstant.PHOTO)
//                    && rootTableData.get(fieldEntry.getKey()) != null && !rootTableData.get(fieldEntry.getKey()).toString().equals("")){
//                mediaFileNameList.add(rootTableDataList.get(0).get(fieldEntry.getKey()).toString());
//            }
//        }
//
//
//        if (multimediaItemList != null && !multimediaItemList.isEmpty()){
//            for(MultimediaItem multimediaItem:multimediaItemList){
//                mediaFileNameList.add(multimediaItem.getMediaPath());
//            }
//        }
        // 20250724 下载无法获取子表中的照片---------------------------------
        List<String> mediaFileNameList = new ArrayList<>();
        String selectByPolygonIdSql = GenerateSqlUtil.generateSelectSqlByField(task.getDatabaseName(), tableName,
                                                                       TableOperationUtil.getPrimaryKey(table),
                                                                       polygonId);
        findMediaFiles(task, table, selectByPolygonIdSql, mediaFileNameList);
        // --------------------------------------------------------------
        if (mediaFileNameList.isEmpty()){
            return ResultMessage.failed("无多媒体文件").toString();
        }
        String tempMediaZipFilePath = StoreMediaFileUtil.zip(mediaPath, mediaFileNameList, null);

        // 利用response上传压缩包
        File tempMediaFile = new File(tempMediaZipFilePath);
        response.setContentType("application/x-zip-compressed");
        response.addHeader("Content-Disposition", "attachment;fileName=photos.zip");
        response.addHeader("Content-Length", String.valueOf(tempMediaFile.length()));
        String result = OtherUtil.uploadFileByResponse(tempMediaFile, response);
        if(result.equals(CommonConstant.FAILED)){
            return ResultMessage.failed(CommonConstant.FAILED).toString();
        }

        // 上传压缩包之后删除产生的中间文件压缩包
        tempMediaFile.delete();
        return ResultMessage.success(null).toString();
    }
    private void findMediaFiles(Task task, Table table, String sql, List<String> mediaFileNameList){

        List<Map<String, Object>> rootTableDataList = baseService.selectData(sql);
        if (rootTableDataList == null || rootTableDataList.isEmpty()){
            return;
        }
        for (Map<String, Object> rootTableData: rootTableDataList){
            Long polygonId = Long.parseLong(rootTableData.get(TableOperationUtil.getPrimaryKey(table)).toString());

            String mediaTableName = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), table.getKey(), true, false);
            List<MultimediaItem> tmp = multimediaService.selectMultiMedia(mediaTableName, polygonId);
            if(tmp!=null) {
                for(MultimediaItem multimediaItem:tmp){
                    mediaFileNameList.add(multimediaItem.getMediaPath());
                }
            }

            // 检查下表中是否有表字段的 type 是 photo，若有，将该字段值对应的路径存放在 mediaFileNameList 中
            for (Map.Entry<String,Field> fieldEntry : table.getFields().entrySet()){
                if (fieldEntry.getValue().getType() != null && fieldEntry.getValue().getType().equals(CommonConstant.PHOTO)
                        && rootTableData.get(fieldEntry.getKey()) != null && !rootTableData.get(fieldEntry.getKey()).toString().isEmpty()){
                    // 这里得拼接用户名和任务id
                    mediaFileNameList.add(rootTableData.get(fieldEntry.getKey()).toString());
                }
                else if (fieldEntry.getValue().getAssociate()!=null && !fieldEntry.getValue().getAssociate().isEmpty()){
                    Table table1 = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class).getTables().get(fieldEntry.getValue().getAssociate());
                    String sql1 = GenerateSqlUtil.generateSelectSqlByField(task.getDatabaseName(), fieldEntry.getValue().getAssociate(), TableOperationUtil.getParentID(table1), polygonId);
                    findMediaFiles(task, table1, sql1, mediaFileNameList);
                }else if (fieldEntry.getValue().getCollection()!=null && !fieldEntry.getValue().getCollection().isEmpty()){
                    Table table2 = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class).getTables().get(fieldEntry.getValue().getCollection());
                    String sql2 = GenerateSqlUtil.generateSelectSqlByField(task.getDatabaseName(), fieldEntry.getValue().getCollection(), TableOperationUtil.getParentID(table2), polygonId);
                    findMediaFiles(task, table2, sql2, mediaFileNameList);
                }
            }
        }

    }

     /**
     * 获取某任务的根表下主键为 polygonId 的数据的属性信息返回给网页端或移动端，
     * 其中属性信息的多媒体文件以文件名形式传递
     * @param taskId      任务id
     * @param tableName   表名
     * @param polygonId   数据主键id
     * @param requestor   标记是移动端访问还是网页端访问，返回的结果不一样
     */
    @RequestMapping(value = "getDataById", produces = "text/html;charset=UTF-8")
    public String getDataById(Integer taskId, String tableName, Long polygonId, String requestor) throws Exception{
        Task task = taskService.getTaskById(taskId);
        Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
        Map<String,Table> tablesMap = config.getTables();
        Table table = tablesMap.get(tableName);
        //判断是否是根表
        String primaryKey = TableOperationUtil.getPrimaryKey(table);
        String selectByPolygonIdSql = GenerateSqlUtil.generateSelectSqlByField(task.getDatabaseName(), table.getKey(),
                                                                               primaryKey, polygonId);
        List<Map<String, Object>> rootTableDataList = baseService.selectData(selectByPolygonIdSql);
        // 根据 requestor 将查询到的根表数据整理成不同类型返回
        switch (requestor.toLowerCase()){
            case CommonConstant.BROWSER:
                ResultMessage resultMessage = OtherUtil.checkDataListGetByPolygonId(rootTableDataList);
                if (!resultMessage.isSuccess()){
                    return resultMessage.toString();
                }
                Map<String, Object> result = genResultMapByRootTableData(table , rootTableDataList.get(0) , task, false);
                return ResultMessage.success(result).toString();
            case CommonConstant.ANDROID:
                Table resultTable = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(table , SerializerFeature.DisableCircularReferenceDetect)) , Table.class);
                Integer version = baseService.getVersionByLongId(PostgreSqlUtil.buildTableNameString(task.getDatabaseName() , tableName , false , false) ,
                                                                 PostgreSqlUtil.transformString(primaryKey) , polygonId);
                if (version == null){
                    return ResultMessage.failed("数据库中无该id数据").toString();
                }
                resultTable = changeDataToTable(resultTable , task , rootTableDataList.get(0) , polygonId , version , version);
                // 20250724------------------------------------------
                baseService.decapPhotoInTable(resultTable.getFields());
                // --------------------------------------------------
                return ResultMessage.success(resultTable).toString();
            default:
                return ResultMessage.failed("传入参数出错").toString();
        }
    }

    /**
     * 获取某任务下某个根表中某数据的所有历史版本，
     * 不包括主表中版本，因为该版本已经显示在地图上
     * @param  taskId        任务id
     * @param  tableName     表名
     * @param  polygonId     数据主键id
     */
    @RequestMapping(value="getDataVersion",produces="text/html;charset=UTF-8")
    public String getDataVersionByPolygonId(Integer taskId, String tableName, Long polygonId){
        Task task = taskService.getTaskById(taskId);
        Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
        Table table = config.getTables().get(tableName);
        String selectVersionSql = MessageFormat.format("select version from {0} where {1}={2}",
                                                       PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), table.getKey(), false, true),
                                                       PostgreSqlUtil.transformString(TableOperationUtil.getPrimaryKey(table)),
                                                       polygonId);
        List<Map<String,Object>> dataList = baseService.selectData(selectVersionSql);
        if (dataList == null || dataList.size() == 0){
            return ResultMessage.failed("无历史版本数据").toString();
        }
        List<Integer> resultList = new ArrayList<>();
        for(Map<String,Object> data : dataList){
            resultList.add(Integer.valueOf(data.get(CommonConstant.FIX_FIELD_VERSION).toString()));
        }
        return ResultMessage.success(resultList).toString();
    }

    /**
     * 获取某任务的根表下 polygonId 和 version 对应的数据
     * @param taskId      任务id
     * @param tableName   表名
     * @param polygonId   数据主键id
     * @param version     版本号
     */
    @RequestMapping(value = "getDataByIdAndVersion", produces = "text/html;charset=UTF-8")
    public String getDataByIdAndVersion(Integer taskId, String tableName, Long polygonId, Integer version) throws Exception{
        Task task = taskService.getTaskById(taskId);
        Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
        Map<String,Table> tablesMap = config.getTables();
        Table table = tablesMap.get(tableName);
        String primaryKey = TableOperationUtil.getPrimaryKey(table);
        String selectByPolygonIdSql = GenerateSqlUtil.genSqlByPolygonIdAndVersionId(task.getDatabaseName(), tableName + CommonConstant.HISTORY_SUFFIX,
                                                                                    primaryKey, polygonId, version);

        List<Map<String, Object>> rootTableDataList = baseService.selectData(selectByPolygonIdSql);
        ResultMessage resultMessage = OtherUtil.checkDataListGetByPolygonId(rootTableDataList);
        if(!resultMessage.isSuccess()){
            return resultMessage.toString();
        }
        Map<String,Object> result = genResultMapByRootTableData(table, rootTableDataList.get(0), task, true);
        return ResultMessage.success(result).toString();
    }
    /**
     * 原始移动端下载数据
     * @param  taskId        任务id
     * @param  tableName     表名
     * @param  userId        用户id
     */
    @RequestMapping(value = "getDataByUserId", produces = "text/html;charset=UTF-8")
    public String getDataByUserId(Integer taskId, String tableName, Integer userId){
        Task task = taskService.getTaskById(taskId);
        if(task == null){
            return ResultMessage.failed("当前任务已删除!").toString();
        }
        // 判断该用户是否在对应的任务中
        if(!OtherUtil.isUserInTask(task, userId, taskUserRoleService)){
            return ResultMessage.failed("您不在该任务中!").toString();
        }
        String selectByUserIdSql;
        String dbTableName = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);
        // 调用接口判断该任务下的该 userId 的身份权限，采集员还是审核员
        Integer userWorkRoleNumber = baseService.getUserWorkRole(taskId, userId) ;
        //查询当前用户角色
        User user = userService.findById(userId).get();
        Integer userrolecode = user.getRole();
//        System.out.println(userrolecode);

        if (userWorkRoleNumber == null) {
            //任务不分配的情况
            if (userrolecode<= 3) {
                // 管理员查询所有记录
                selectByUserIdSql = MessageFormat.format(
                        "select * FROM {0} ORDER BY {1} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_CREATE_TIME
                );
            } else {
                // 其他角色，按用户过滤
                selectByUserIdSql = MessageFormat.format(
                        "select * FROM {0} where {1}={3} OR {2}={3} OR {2}=-1 ORDER BY {4} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_COLLECTOR,
                        CommonConstant.FIX_FIELD_REVIEWER,
                        userId,
                        CommonConstant.FIX_FIELD_CREATE_TIME
                );
            }
        }
        else if (userWorkRoleNumber == 0){
            selectByUserIdSql = MessageFormat.format("select * FROM {0} where {1}={2} ORDER BY {3} DESC", dbTableName,
                    CommonConstant.FIX_FIELD_COLLECTOR, userId,
                    CommonConstant.FIX_FIELD_CREATE_TIME);
        }
        else if(userWorkRoleNumber == 1){
            if (task.getIsReviewerRestricted() == 1) {
                // 及时审核：获取自己审核的、还没有分配的和自己采集的数据
//                selectByUserIdSql = MessageFormat.format("select * FROM {0} where status != 2 and ({1} = {2} or {1} = -1 or {3} = {2}) ORDER BY {4} DESC",
//                        dbTableName,
//                        CommonConstant.FIX_FIELD_REVIEWER, userId,
//                        CommonConstant.FIX_FIELD_COLLECTOR,
//                        CommonConstant.FIX_FIELD_CREATE_TIME);
                selectByUserIdSql = MessageFormat.format("select * FROM {0} where  ({1} = {2} or {1} = -1 or {3} = {2}) ORDER BY {4} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_REVIEWER, userId,
                        CommonConstant.FIX_FIELD_COLLECTOR,
                        CommonConstant.FIX_FIELD_CREATE_TIME);
            } else {
                // 非及时审核：获取自己审核的或自己采集的数据
                selectByUserIdSql = MessageFormat.format("select * FROM {0} where ({1} = {2} or {3} = {2}) ORDER BY {4} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_REVIEWER, userId,
                        CommonConstant.FIX_FIELD_COLLECTOR,
                        CommonConstant.FIX_FIELD_CREATE_TIME);
            }
        }
        else{
            return ResultMessage.failed("身份权限出错").toString();
        }

        // 获取根表数据中 reviewer 字段值为 userId 的所有记录
        List<Map<String, Object>> rootTableDataList = baseService.selectData(selectByUserIdSql);
        if(rootTableDataList == null || rootTableDataList.size() == 0){
            return ResultMessage.failed("获取记录为空").toString();
        }
        Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
        Map<String,Table> tablesMap = config.getTables();
        Table table = tablesMap.get(tableName);
        // 封装记录成 Table 类, 并添加在 List中返回给安卓端
        List<Table> tablesResultList = new ArrayList<>();
        String primaryKey = TableOperationUtil.getPrimaryKey(table);
        for(Map<String, Object> rootTableData : rootTableDataList){
            Long polygonId = Long.valueOf(rootTableData.get(TableOperationUtil.getPrimaryKey(table)).toString());
//            Table resultTable = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(table, SerializerFeature.DisableCircularReferenceDetect)),
//                                                  Table.class);
            Table resultTable = JSON.parseObject(JSON.toJSONString(table, SerializerFeature.DisableCircularReferenceDetect), Table.class);
//            resultTable = cleanTableForAndroid(resultTable);

            Integer versionCode = baseService.getVersionByLongId(dbTableName, PostgreSqlUtil.transformString(primaryKey), polygonId);
            if (versionCode == null){
                return ResultMessage.failed("数据库中无该id数据").toString();
            }
            resultTable = changeDataToTable(resultTable, task, rootTableData, polygonId,versionCode,versionCode);
            // 20250724------------------------------------------
            baseService.decapPhotoInTable(resultTable.getFields());
            // --------------------------------------------------
            tablesResultList.add(resultTable);
        }
        return ResultMessage.success(tablesResultList).toStringByDisableCircularReference();
    }
    /**
     * 移动端下载数据
     * @param  taskId        任务id
     * @param  tableName     表名
     * @param  userId        用户id
     * @param  idList        ID列表，用于筛选特定数据
     */
    @RequestMapping(value = "getDatatoAndroid", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    @ResponseBody
    public String getDatatoAndroid(@RequestParam Integer taskId,
                                  @RequestParam String tableName,
                                  @RequestParam Integer userId,
                                  @RequestParam(required = false) String idList) {
        Task task = taskService.getTaskById(taskId);
        if (task == null) {
            return ResultMessage.failed("当前任务已删除!").toString();
        }

        if (!OtherUtil.isUserInTask(task, userId, taskUserRoleService)) {
            return ResultMessage.failed("您不在该任务中!").toString();
        }

        // 构造SQL
        String selectByUserIdSql;
        String dbTableName = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);
        Integer userWorkRoleNumber = baseService.getUserWorkRole(taskId, userId);
        User user = userService.findById(userId).get();
        Integer userrolecode = user.getRole();

        if (userWorkRoleNumber == null) {
            if (userrolecode <= 3) {
                selectByUserIdSql = MessageFormat.format(
                        "select * FROM {0} ORDER BY {1} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_CREATE_TIME
                );
            } else {
                selectByUserIdSql = MessageFormat.format(
                        "select * FROM {0} where {1}={3} OR {2}={3} OR {2}=-1 ORDER BY {4} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_COLLECTOR,
                        CommonConstant.FIX_FIELD_REVIEWER,
                        userId,
                        CommonConstant.FIX_FIELD_CREATE_TIME
                );
            }
        } else if (userWorkRoleNumber == 0) {
            selectByUserIdSql = MessageFormat.format(
                    "select * FROM {0} where {1}={2} ORDER BY {3} DESC",
                    dbTableName,
                    CommonConstant.FIX_FIELD_COLLECTOR, userId,
                    CommonConstant.FIX_FIELD_CREATE_TIME
            );
        } else if (userWorkRoleNumber == 1) {
            if (task.getIsReviewerRestricted() == 1) {
                selectByUserIdSql = MessageFormat.format(
                        "select * FROM {0} where  ({1} = {2} or {1} = -1 or {3} = {2}) ORDER BY {4} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_REVIEWER, userId,
                        CommonConstant.FIX_FIELD_COLLECTOR,
                        CommonConstant.FIX_FIELD_CREATE_TIME
                );
            } else {
                selectByUserIdSql = MessageFormat.format(
                        "select * FROM {0} where ({1} = {2} or {3} = {2}) ORDER BY {4} DESC",
                        dbTableName,
                        CommonConstant.FIX_FIELD_REVIEWER, userId,
                        CommonConstant.FIX_FIELD_COLLECTOR,
                        CommonConstant.FIX_FIELD_CREATE_TIME
                );
            }
        } else {
            return ResultMessage.failed("身份权限出错").toString();
        }

        // 处理 idList 字符串
        if (idList != null && !idList.trim().isEmpty()) {
            String[] ids = idList.split(",");
            List<Long> idListParsed = Arrays.stream(ids)
                    .map(String::trim)
                    .filter(s -> !s.isEmpty())
                    .map(Long::valueOf)
                    .collect(Collectors.toList());

            if (!idListParsed.isEmpty()) {
                String primaryKey = TableOperationUtil.getPrimaryKey(
                        JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class).getTables().get(tableName)
                );

                StringBuilder inCondition = new StringBuilder();
                inCondition.append(" AND ").append(PostgreSqlUtil.transformString(primaryKey)).append(" IN (");
                for (int i = 0; i < idListParsed.size(); i++) {
                    inCondition.append(idListParsed.get(i));
                    if (i < idListParsed.size() - 1) {
                        inCondition.append(",");
                    }
                }
                inCondition.append(")");

                int whereIndex = selectByUserIdSql.toUpperCase().indexOf(" WHERE ");
                int orderByIndex = selectByUserIdSql.lastIndexOf(" ORDER BY");

                if (orderByIndex != -1) {
                    if (whereIndex != -1) {
                        selectByUserIdSql = selectByUserIdSql.substring(0, orderByIndex) +
                                inCondition.toString() +
                                selectByUserIdSql.substring(orderByIndex);
                    } else {
                        String inConditionWithWhere = inCondition.toString().replaceFirst(" AND ", " WHERE ");
                        selectByUserIdSql = selectByUserIdSql.substring(0, orderByIndex) +
                                inConditionWithWhere +
                                selectByUserIdSql.substring(orderByIndex);
                    }
                } else {
                    if (whereIndex != -1) {
                        selectByUserIdSql += inCondition.toString();
                    } else {
                        String inConditionWithWhere = inCondition.toString().replaceFirst(" AND ", " WHERE ");
                        selectByUserIdSql += inConditionWithWhere;
                    }
                }
            }
        }

        List<Map<String, Object>> rootTableDataList = baseService.selectData(selectByUserIdSql);
        if (rootTableDataList == null || rootTableDataList.isEmpty()) {
            return ResultMessage.failed("获取记录为空").toString();
        }

        Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
        Table table = config.getTables().get(tableName);
        List<Table> tablesResultList = new ArrayList<>();
        String primaryKey = TableOperationUtil.getPrimaryKey(table);

        for (Map<String, Object> rootTableData : rootTableDataList) {
            Long polygonId = Long.valueOf(rootTableData.get(primaryKey).toString());
            Table resultTable = JSON.parseObject(JSON.toJSONString(table, SerializerFeature.DisableCircularReferenceDetect), Table.class);
            Integer versionCode = baseService.getVersionByLongId(dbTableName, PostgreSqlUtil.transformString(primaryKey), polygonId);

            if (versionCode == null) {
                return ResultMessage.failed("数据库中无该id数据").toString();
            }

            resultTable = changeDataToTable(resultTable, task, rootTableData, polygonId, versionCode, versionCode);
            baseService.decapPhotoInTable(resultTable.getFields());
            tablesResultList.add(resultTable);
        }

        return ResultMessage.success(tablesResultList).toStringByDisableCircularReference();
    }





    /**
     * 清理 Table和其具体字段中 Android 不需要的字段
     */
    private void cleanTableForAndroid(Map<String, Field> fieldMap) {
        if (fieldMap != null) {
            for (Field field : fieldMap.values()) {
                field.setSelects(null);
                field.setShowSelects(null);
                field.setScript(null);
                field.setShow(null);
//              field.setResultType(null);
                field.setMode(null);
                field.setSelect(null);
                field.setGroups(null);
                field.setCollectionValue(null);
                // 清空基础字段
                field.setViewKey(null);
//                field.setDbType(null);
//                field.setName(null);
//                field.setType(null);
//                field.setAutoDate(null);
                field.setTooltips(null);
                field.setCheck(null);
                field.setLastSelectValue(null);
            }
        }
    }

    /**
     * 移动端用于同步审核后的状态，需要同时获取审核通过和未通过的数据
     *
     * @param  taskId        任务id
     * @param  userId        用户id
     */
    @RequestMapping(value = "syncReviewStatus", produces = "text/html;charset=UTF-8")
    public String syncReviewStatus(Integer taskId, Integer userId){
        Task task = taskService.getTaskById(taskId);
        if(task == null){
            return ResultMessage.failed("当前任务已删除!").toString();
        }
        // 判断该用户是否在对应的任务中
        if(!OtherUtil.isUserInTask(task, userId, taskUserRoleService)){
            return ResultMessage.failed("您不在该任务中!").toString();
        }
        Map<String,Table> rootTables = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class).getRootTables();
        List<Map<String,Object>> result = new ArrayList<>();
        rootTables.forEach((key,value) -> {
            String primaryKey = TableOperationUtil.getPrimaryKey(rootTables.get(key));
            String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), key, false, false);
            List<Map<String,Object>> notPassDataIdList = baseService.getNotPassDataId(tableNameInDb, PostgreSqlUtil.transformString(primaryKey), userId);
            Map<String,Object> map = new HashMap<>();
            map.put("tableName",key);
            if (notPassDataIdList == null || notPassDataIdList.size() == 0){
                map.put("data",null);
            }
            else{
                List<Map<String,Object>> resultValueList = new ArrayList<>();
                for (Map<String,Object> notPassDataMap : notPassDataIdList){
                    Map<String,Object> idReasonMap = new HashMap<>();
                    idReasonMap.put("id",notPassDataMap.get(primaryKey));
                    idReasonMap.put("status", notPassDataMap.get(CommonConstant.FIX_FIELD_STATUS));
                    idReasonMap.put("reason", notPassDataMap.get(CommonConstant.FIX_FIELD_REASON));
                    resultValueList.add(idReasonMap);
                }
                map.put("data",resultValueList);
            }
            result.add(map);

        });
        return ResultMessage.success(result).toString();
    }


    /**
     * 获取某任务的根表下所有数据的 id 和 shape，以 Feature 类形式组织返回给前端
     * @param  taskId        任务id
     * @param  tableName     表名
     */
    @RequestMapping(value = "getAllData", produces = "text/html;charset=UTF-8")
    public String getAllDataForTaskIdAndTableName(Integer taskId, String tableName){
        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);
        String geometryFiledName = CheckTableDataUtil.getGeometryFieldName(table);
        String selectAllDataSql = MessageFormat.format(SqlStringConstant.SELECT_ALLDATA_SQL, tableNameInDb);
        List<Map<String, Object>> rootTableDataList = baseService.selectData(selectAllDataSql);
        if (rootTableDataList == null || rootTableDataList.size() == 0){
            return ResultMessage.success(null).toString();
        }
        else
        {
            List<Feature> featureList = changeRootTableDataToFeatureList(task, tableName, geometryFiledName,
                                                                         rootTableDataList, false,null,null);
            return ResultMessage.success(featureList).toStringByDisableCircularReference();
        }
    }

    /**
     * 获取某任务的某根表下所有数据库类型为 text 的字段名，包括数据库中的字段名和中文名(如果有的话)
     * 注意这里数据库类型为 text 是网页端选择的类型，并非存在数据库中的类型
     */
    @RequestMapping(value = "getFieldNames", produces = "text/html;charset=UTF-8")
    public String getFieldNames(Integer taskId, String tableName){
        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class).getTables().get(tableName);
        List<String> fieldNameList = CheckTableDataUtil.getTextFieldName(table);
        Map<String, Field> fields = table.getFields();
        if (fieldNameList.isEmpty()){
            return ResultMessage.success(null).toString();
        }

        List<Map<String,String>> result = new ArrayList<>();
        for (String fieldName : fieldNameList){
            Map<String,String> tempMap = new HashMap<>();
            tempMap.put("key",fieldName);
            String name = fields.get(fieldName).getName();
            if (name != null && !"".equals(name)){
                tempMap.put("name",name);
            }
            else{
                tempMap.put("name","");
            }
            result.add(tempMap);
        }
        return ResultMessage.success(result).toString();
    }

    /**
     * 根据任务id，表名，字段名和模糊搜索的关键字 searchKey 获取数据。
     * 这个地方是搜索任务位置，因此返回的是数据的中心点模糊搜索采用
     * field like '%searchKey%'的SelectSql样式。全局搜索
     * @param  taskId        任务id
     * @param  tableName     表名
     * @param  fieldName     字段
     * @param  searchKey     模糊搜索的关键字
     */
    @RequestMapping(value = "getAllFuzzySearchDataCenterPoint", produces = "text/html;charset=UTF-8")
    public String getAllFuzzySearchDataCenterPoint(Integer taskId, String tableName, String fieldName,
                                                   String searchKey, int pageNum){
        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName,false,false);
        String fieldNameInDb = PostgreSqlUtil.transformString(fieldName);
        String geometryFieldName =  PostgreSqlUtil.transformString(CheckTableDataUtil.getGeometryFieldName(table));
        String orderBy = "update_time ASC";
        PageHelper.startPage(pageNum, CommonConstant.PAGE_SIZE, orderBy);
        Page<Map<String, Object>> pageData = baseService.getAllFuzzySearchDataCenterPoint(tableNameInDb, fieldNameInDb,
                                                                                          geometryFieldName,
                                                                                          "\'%" + searchKey + "%\'");
        return ResultMessage.success(getDataTable(pageData, table, task, true)).toString();
    }

    /**
     * 根据任务id，表名，字段名和模糊搜索的关键字searchKey获取数据，
     * 模糊搜索采用 field like '%searchKey%'的SelectSql样式。
     *
     * 模糊搜索分成两个，一个是缩放等级小返回通过geohash聚类的结果，
     * 另一个是缩放等级大，返回屏幕范围内且与关键字匹配的具体数据。
     * 与上面的获取全部数据那里相同，缩放精度及经纬度范围见 getCountByGeoHash() 方法介绍
     * @param  taskId        任务id
     * @param  tableName     表名
     * @param  fieldName     字段
     * @param  searchKey     模糊搜索的关键字
     */
    @RequestMapping(value = "getCountByFuzzySearchAndGeohash", produces = "text/html;charset=UTF-8")
    public String getCountByFuzzySearchAndGeohash(Integer taskId, String tableName, String fieldName,String searchKey,
                                                  Integer accuracy, Double longitudeMin, Double latitudeMin,
                                                  Double longitudeMax, Double latitudeMax){
        Task task = taskService.getTaskById(taskId);
        if (tableName == null || "".equals(tableName) || fieldName == null || "".equals(fieldName)){
            return ResultMessage.failed("未选择表或字段").toString();
        }
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
        String geometryFieldName = CheckTableDataUtil.getGeometryFieldName(table);
        String selectSqlPosteriorPart = " where " + PostgreSqlUtil.transformString(fieldName) + " like \'%" + searchKey + "%\'";
        String selectSql = MessageFormat.format(SqlStringConstant.SELECT_SQL_BY_GEOHASH,
                                                PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false),
                                                PostgreSqlUtil.transformString(geometryFieldName), accuracy,
                                                longitudeMin, latitudeMin, longitudeMax, latitudeMax,
                                                selectSqlPosteriorPart);
        List<Map<String,Object>> dataList = baseService.selectData(selectSql);
        if (dataList == null || dataList.size() == 0){
            return ResultMessage.success(null).toString();
        }
        else{
            List<Map<String,Object>> result = OtherUtil.genFeatureCountList(dataList);
            return ResultMessage.success(result).toStringByDisableCircularReference();
        }
    }

    /**
     * 前端地图缩放到一定等级后，返回该范围内且与关键字匹配的所有数据
     * 该方法与getDataByRangeIntersection()方法区别在于该方法多出关键字，
     * 查询的 sql 也较复杂
     */
    @RequestMapping(value = "getDataByFuzzySearchAndRangeIntersection", produces = "text/html;charset=UTF-8")
    public String getDataByFuzzySearchAndRangeIntersection(Integer taskId, String tableName, String fieldName, String searchKey,
                                                           Double longitudeMin, Double latitudeMin, Double longitudeMax,
                                                           Double latitudeMax){
        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);

        String selectSqlPrecedingPart = MessageFormat.format(SqlStringConstant.SELECTCENTER_SQL_BY_RANGE_INTERSECTION, tableNameInDb,
                                                             PostgreSqlUtil.transformString(TableOperationUtil.getPrimaryKey(table)),
                                                             PostgreSqlUtil.transformString(CheckTableDataUtil.getGeometryFieldName(table)),
                                                             longitudeMin, latitudeMin, longitudeMax, latitudeMax);
        String selectSqlPosteriorPart = "and " + PostgreSqlUtil.transformString(fieldName) + " like \'%" + searchKey + "%\'";
        List<Map<String,Object>> rootTableDataList = baseService.selectData(selectSqlPrecedingPart + selectSqlPosteriorPart);
        if (rootTableDataList == null || rootTableDataList.size() == 0){
            return ResultMessage.success(null).toString();
        }
        else{
            List<Feature> featureList = changeRootTableDataToFeatureList(task, tableName, CommonConstant.GEOMETRY,
                                                                         rootTableDataList, false, null,null);
            return ResultMessage.success(featureList).toStringByDisableCircularReference();
        }
    }

    /**
     * 前端地图缩放到一定等级后，返回该范围内的所有数据
     */
//    @RequestMapping(value = "getDataByRangeIntersection", produces = "text/html;charset=UTF-8")
//    public String getDataByRangeIntersection(Integer taskId, String tableName, Double longitudeMin, Double latitudeMin,
//                                             Double longitudeMax, Double latitudeMax){
//        Task task = taskService.getTaskById(taskId);
//        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
//        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);
//        String selectSql = MessageFormat.format(SqlStringConstant.SELECT_SQL_BY_RANGE_INTERSECTION, tableNameInDb,
//                                                PostgreSqlUtil.transformString(TableOperationUtil.getPrimaryKey(table)),
//                                                PostgreSqlUtil.transformString(CheckTableDataUtil.getGeometryFieldName(table)),
//                                                PostgreSqlUtil.transformString(TableOperationUtil.getUploadNameFieldName(table)),
//                                                longitudeMin, latitudeMin, longitudeMax, latitudeMax);
//        List<Map<String,Object>> rootTableDataList = baseService.selectData(selectSql);
//        if (rootTableDataList == null || rootTableDataList.size() == 0)
//        {
//            return ResultMessage.success(null).toString();
//        }
//        else{
//            List<Feature> featureList = changeRootTableDataToFeatureList(task, tableName, CheckTableDataUtil.getGeometryFieldName(table),
//                                                                         rootTableDataList, false,null,null);
//            return ResultMessage.success(featureList).toStringByDisableCircularReference();
//        }
//    }

    /**
     * 前端地图缩放到一定等级后，返回该范围内的所有数据,以及该数据的是否被抽取，以及抽取的顺序
     */
    @RequestMapping(value = "getDataByRangeIntersection", produces = "text/html;charset=UTF-8")
    public String getDataByRangeIntersection(Integer taskId, String tableName, Double longitudeMin,
                                                        Double latitudeMin, Double longitudeMax, Double latitudeMax
                                                       ) {
        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);

        String primaryKeyField = TableOperationUtil.getPrimaryKey(table);
        String geomField = CheckTableDataUtil.getGeometryFieldName(table);
        String uploadNameField = TableOperationUtil.getUploadNameFieldName(table);
        // ⚠️ 几何字段为空，直接返回空结果，避免 SQL 报错
        if (geomField == null || geomField.trim().isEmpty()) {
            return ResultMessage.success(Collections.emptyList()).toString();
        }
        String selectSql;
        if (table.isRoot()) {
            // 根表查询包含 collector 和 reviewer
            selectSql = MessageFormat.format(SqlStringConstant.SELECT_SQL_BY_RANGE_INTERSECTION,
                    tableNameInDb,
                    PostgreSqlUtil.transformString(primaryKeyField),
                    PostgreSqlUtil.transformString(geomField),
                    PostgreSqlUtil.transformString(uploadNameField),
                    longitudeMin, latitudeMin, longitudeMax, latitudeMax
            );
        } else {
            // 非根表不包含 collector 和 reviewer，构造自定义 SQL
            selectSql = String.format(
                    "SELECT %s, %s FROM %s WHERE ST_Intersects(ST_MakeEnvelope(%f, %f, %f, %f, 4490), st_setsrid(ST_GeomFromGeoJSON(%s), 4490))",
                    PostgreSqlUtil.transformString(primaryKeyField),
                    PostgreSqlUtil.transformString(geomField),
                    tableNameInDb,
                    longitudeMin, latitudeMin, longitudeMax, latitudeMax,
                    PostgreSqlUtil.transformString(geomField)
            );
        }

        List<Map<String, Object>> rootTableDataList = baseService.selectData(selectSql);
        if (rootTableDataList == null || rootTableDataList.isEmpty()) {
            return ResultMessage.success(null).toString();
        } else {
            List<Feature> featureList = changeRootTableDataToFeatureList(task, tableName, CheckTableDataUtil.getGeometryFieldName(table),
                                                                         rootTableDataList, false,null,null);
            return ResultMessage.success(featureList).toStringByDisableCircularReference();
        }
    }

    // TODO 统一前后端状态码的含义
    /**
     * 获取某页的数据详情，其中也包括数据共多少页(获取全部数据的过程)
     * @param status 数据状态有 -1、0、1、2，分别代表审核未通过、未采集、已采集、审核通过
     */
//    @RequestMapping(value="getDataByPageNum",produces="text/html;charset=UTF-8")
//    public String getDataByPageNum(Integer taskId, String tableName, Integer workerId, int status,
//                                   int pageNum, @RequestParam(defaultValue = "10") int pageSize){
//        Task task = taskService.getTaskById(taskId);
//        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName,false,false);
//        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
//        String orderBy = "update_time ASC";
//        PageHelper.startPage(pageNum, pageSize, orderBy);
//        Page<Map<String, Object>> pageData = searchPageService.getPageDataByWorkerAndStatus(tableNameInDb, workerId, status);
//        return ResultMessage.success(getDataTable(pageData, table, task, false)).toString();
//    }
    @RequestMapping(value = "getDataByPageNum", produces = "text/html;charset=UTF-8")
    public String getDataByPageNum(Integer taskId, String tableName, Integer workerId, int status,
                                   int pageNum, @RequestParam(defaultValue = "10") int pageSize) {
        Task task = taskService.getTaskById(taskId);

        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class)
                .getTables().get(tableName);

        Page<Map<String, Object>> pageData;

        if (table.isRoot()) {
            String orderBy = "update_time ASC";
            PageHelper.startPage(pageNum, pageSize, orderBy);
            pageData = searchPageService.getPageDataByWorkerAndStatus(tableNameInDb, workerId, status);
        } else {
            String orderBy = "\"ID\" ASC";
            PageHelper.startPage(pageNum, pageSize, orderBy);
            List<Map<String, Object>> list = searchPageService.getPageDataByWorkerNoStatus(tableNameInDb);
            // 为了统一格式，包装为 Page 对象（可以手动构造）
            pageData = new Page<>();
            pageData.addAll(list);
            pageData.setPageNum(1);
            pageData.setPageSize(list.size());
            pageData.setTotal(list.size());
        }

        return ResultMessage.success(getDataTable(pageData, table, task, false)).toString();
    }



    /**
     * 获取某页的数据详情，其中也包括数据共多少页(获取模糊匹配数据的过程)
     */
    @RequestMapping(value="getFuzzySearchDataByPageNum",produces="text/html;charset=UTF-8")
    public String getFuzzySearchDataByPageNum(Integer taskId, String tableName, String fieldName, String searchKey,
                                              int pageNum){
        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName,false,false);
        String fieldNameInDb = PostgreSqlUtil.transformString(fieldName);
        String orderBy = "update_time ASC";
        PageHelper.startPage(pageNum, CommonConstant.PAGE_SIZE, orderBy);
        Page<Map<String, Object>> pageData = searchPageService.getPageDataByFuzzySearch(tableNameInDb, fieldNameInDb, "\'%" + searchKey + "%\'");
        return ResultMessage.success(getDataTable(pageData, table, task, false)).toString();
    }

    /**
    /**
     * 将 Page<T> 中数据按照特定格式组织起来，封装成一个方法方便其他接口调用
     */
    private Map<String,Object> getDataTable(Page<Map<String, Object>> pageData, Table table, Task task,
                                            boolean extractCenterPoint){
        String geometryFieldName = CheckTableDataUtil.getGeometryFieldName(table);
        String primaryKey = TableOperationUtil.getPrimaryKey(table);
        Map<String,Object> result = new HashMap<>();
        List<Map<String, Object>> dataList = pageData.getResult();
        if (dataList != null && dataList.size() != 0){
            List<Object> dataInfoList = new ArrayList<>();
            List<Object> dataCoordinatesList = new ArrayList<>();
            dataList.forEach(o ->{
                Feature feature = new Feature();
                feature.setType(CommonConstant.FEATURE);
                Map<String,String> propertiesMap = new HashMap<>();
                if (o.containsKey(primaryKey)){
                    propertiesMap.put("id", o.get(primaryKey).toString());
                    feature.setProperties(propertiesMap);
                }
                // 添加 geometry 字段（如果存在）
                if (extractCenterPoint){
                    if (o.containsKey(CommonConstant.GEOMETRY)){
                        feature.setGeometry(JSON.toJavaObject(JSON.parseObject(o.get(CommonConstant.GEOMETRY).toString()),
                                                              GeometryType.class));
                        dataCoordinatesList.add(feature);
                    }
                }
                else{
                    if (o.containsKey(geometryFieldName)){
                        feature.setGeometry(JSON.toJavaObject(JSON.parseObject(o.get(geometryFieldName).toString()),
                                                              GeometryType.class));
                        dataCoordinatesList.add(feature);
                    }
                }
                // 添加属性信息
                //根表和非根表分开进行处理
                try {
                    if (table.isRoot()) {
                        dataInfoList.add(genResultMapByRootTableData(table, o, task, false));
                    } else {
                        dataInfoList.add(genResultMapBySubTableData(table, o, task));
                    }
                } catch (Exception e) {
                    e.printStackTrace(); // 可替换为日志
                }
            });
            result.put("dataInfo",dataInfoList);
            result.put("dataCoordinates",dataCoordinatesList);
            result.put("dataPageNum",pageData.getPages());
            return result;
        }
        else{
            return null;
        }
    }


    /**
     * 把获取的数据填进Table中部分相同操作封装成一个方法，便于getDataByUserId()和getDataById()使用
     */
    private Table changeDataToTable(Table table, Task task, Map<String, Object> rootTableData, Long polygonId,
                                    int versionCode, int maxVersionCodeInDB){
        table.getFields().remove(CommonConstant.FIX_FIELD_CREATE_TIME);
        table.getFields().remove(CommonConstant.FIX_FIELD_UPDATE_TIME);
        Map<String, Field> fieldsMap = table.getFields();
        Map<String,String> associateTableMap = CheckTableDataUtil.getAssociateField(table, task.getConfig());
        Map<String,String> collectorTableMap = CheckTableDataUtil.getCollectionField(table, task.getConfig());
        for (Map.Entry<String, Object> rootTableDataEntry : rootTableData.entrySet()){
            String fieldName = rootTableDataEntry.getKey();
            Object fieldValue = rootTableDataEntry.getValue();

            if (fieldName.equals(CheckTableDataUtil.getGeometryFieldName(table))){
                fieldsMap.get(fieldName).setValue(ShapeTypeUtil.changeGeometryToArcGIS(fieldValue.toString()));
            }
            else if (!fieldName.equals(CommonConstant.FIX_FIELD_CREATE_TIME)
                    && !fieldName.equals(CommonConstant.FIX_FIELD_UPDATE_TIME)){
                Field field = fieldsMap.get(fieldName);
                if (field.getType() != null && field.getType().equals(CommonConstant.PHOTO)
                            && fieldValue != null && ! fieldValue.toString().equals("")){
                    fieldsMap.get(fieldName).setValue(fieldValue.toString().substring(fieldValue.toString().lastIndexOf('/') + 1));
                    continue;
                }
                fieldsMap.get(fieldName).setValue(fieldValue);
            }
        }
        if(associateTableMap.size()!=0 || collectorTableMap.size()!=0){
            table = recursiveChangeDataToTable(table,task.getDatabaseName(),polygonId, task.getConfig(),
                                               associateTableMap,collectorTableMap,versionCode,maxVersionCodeInDB);
        }
        List<MultimediaItem> multiMediaItemList;
        if (versionCode == maxVersionCodeInDB){

            String mediatableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), table.getKey(), true, false);
            multiMediaItemList = multimediaService.selectMultiMedia(mediatableNameInDb, polygonId);
        }
        else{
            String mediatableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), table.getKey(), true, true);
            multiMediaItemList = multimediaService.selectHistoryMultiMedia(mediatableNameInDb, polygonId, versionCode);
        }
        String cameraFieldName = TableOperationUtil.getCameraFieldName(table);
        if (cameraFieldName != null && !cameraFieldName.equals("")){
            fieldsMap.get(cameraFieldName).setValue(multiMediaItemList);
        }
        table.setFields(fieldsMap);
        cleanTableForAndroid(table.getFields());
        return table;
    }

    /**
     * 递归的获取关联表数据，并将关联表数据放进根表数据对应的Table中
     */
//    private Table recursiveChangeDataToTable(Table table, String databaseName, Long polygonId, String configString,
//                                             Map<String,String> associateTableMap, Map<String,String> collectorTableMap,
//                                             int versionCode, int maxVersionCodeInDB){
//        Map<String, Field> tableFields = table.getFields();
//        Config config = JSON.toJavaObject(JSON.parseObject(configString), Config.class);
//        Map<String,Table> tables = config.getTables();
//        if(associateTableMap.size()!=0){
//            for(Map.Entry<String,String> associateEntry:associateTableMap.entrySet()){
//                Table associateTable = tables.get(associateEntry.getKey());
//                String selectSql;
//                if(versionCode == maxVersionCodeInDB){
//                    selectSql = GenerateSqlUtil.generateSelectSqlByField(databaseName, associateEntry.getKey(),
//                                                                         associateEntry.getValue(), polygonId);
//                }
//                else{
//                    selectSql = GenerateSqlUtil.genSqlByPolygonIdAndVersionId(databaseName, associateEntry.getKey() + CommonConstant.HISTORY_SUFFIX,
//                                                                              associateEntry.getValue(), polygonId, versionCode);
//                }
//
//                List<Map<String, Object>> dataList = baseService.selectData(selectSql);
//                if(dataList == null || dataList.size() == 0)
//                {
//                    continue;
//                }
//                Map<String, Object> associateData = dataList.get(0);
//                String primaryKey = TableOperationUtil.getPrimaryKey(associateTable);
//                Map<String, Field> associateTableFields = new HashMap<>(associateTable.getFields());
//                associateTableFields.remove(CommonConstant.FIX_FIELD_VERSION);
//                associateTableFields = putDataToMap(associateData,associateTableFields);
//                associateTable.setFields(associateTableFields);
//                Long associatePolygonId = Long.valueOf(associateData.get(primaryKey).toString());
//                Map<String,String> childAssociateTableMap = CheckTableDataUtil.getAssociateField(associateTable, configString);
//                Map<String,String> childCollectorTableMap = CheckTableDataUtil.getCollectionField(associateTable, configString);
//                if(childAssociateTableMap.size()!=0 || childCollectorTableMap.size()!=0)
//                {
//                    associateTable = recursiveChangeDataToTable(associateTable,databaseName,associatePolygonId, configString,
//                                                                childAssociateTableMap,childCollectorTableMap,versionCode, maxVersionCodeInDB);
//                }
//                Field tempField = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(tableFields.get(associateEntry.getKey()), SerializerFeature.DisableCircularReferenceDetect)),
//                                                    Field.class);
//                tempField.setValue(associateTable.getFields());
//                tableFields.remove(associateEntry.getKey());
//                tableFields.put(associateEntry.getKey(), tempField);
//            }
//        }
//        if(collectorTableMap.size()!=0)
//        {
//            for(Map.Entry<String,String> collectorEntry:collectorTableMap.entrySet())
//            {
//                Table collectorTable = tables.get(collectorEntry.getKey());
//                String selectSql;
//                if(versionCode == maxVersionCodeInDB)
//                {
//                    selectSql = GenerateSqlUtil.generateSelectSqlByField(databaseName, collectorEntry.getKey(),
//                                                                         collectorEntry.getValue(), polygonId);
//                }
//                else
//                {
//                    selectSql = GenerateSqlUtil.genSqlByPolygonIdAndVersionId(databaseName, collectorEntry.getKey() + CommonConstant.HISTORY_SUFFIX,
//                                                                              collectorEntry.getValue(), polygonId, versionCode);
//                }
//
//                List<Map<String, Object>> dataList = baseService.selectData(selectSql);
//                if (dataList == null || dataList.size() == 0)
//                {
//                    continue;
//                }
//                List<Map<String,Field>> result = new ArrayList<>();
//                for(Map<String, Object> data:dataList)
//                {
//                    Map<String, Field> collectorTableFields = new HashMap<>(collectorTable.getFields());
//                    collectorTableFields.remove(CommonConstant.FIX_FIELD_VERSION);
//                    collectorTableFields = putDataToMap(data, collectorTableFields);
//                    result.add(collectorTableFields);
//                }
//                String primaryKey = TableOperationUtil.getPrimaryKey(collectorTable);
//                Map<String,String> childAssociateTableMap = CheckTableDataUtil.getAssociateField(collectorTable, configString);
//                Map<String,String> childCollectorTableMap = CheckTableDataUtil.getCollectionField(collectorTable, configString);
//                for(Map<String, Object> data:dataList)
//                {
//                    Long collectorPolygonId = Long.valueOf(data.get(primaryKey).toString());
//                    if(childAssociateTableMap.size()!=0 || childCollectorTableMap.size()!=0)
//                    {
//                        collectorTable = recursiveChangeDataToTable(collectorTable,databaseName,collectorPolygonId, configString,
//                                                                    childAssociateTableMap,childCollectorTableMap,versionCode,
//                                                                    maxVersionCodeInDB);
//                    }
//                }
//                tableFields.get(collectorEntry.getKey()).setValue(result);
//                Field tempField = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(tableFields.get(collectorEntry.getKey()), SerializerFeature.DisableCircularReferenceDetect)),
//                                                    Field.class);
//                tempField.setValue(result);
//                tableFields.remove(collectorEntry.getKey());
//                tableFields.put(collectorEntry.getKey(), tempField);
//            }
//        }
//        table.setFields(tableFields);
//        return table;
//    }
    private Table recursiveChangeDataToTable(Table table, String databaseName, Long polygonId, String configString,
                                             Map<String,String> associateTableMap, Map<String,String> collectorTableMap,
                                             int versionCode, int maxVersionCodeInDB){
        Map<String, Field> tableFields = table.getFields();
        Config config = JSON.toJavaObject(JSON.parseObject(configString), Config.class);
        Map<String,Table> tables = config.getTables();

        if(associateTableMap.size() != 0){
            for(Map.Entry<String,String> associateEntry : associateTableMap.entrySet()){
                Table associateTable = tables.get(associateEntry.getKey());
                String selectSql;
                if(versionCode == maxVersionCodeInDB){
                    selectSql = GenerateSqlUtil.generateSelectSqlByField(databaseName, associateEntry.getKey(),
                            associateEntry.getValue(), polygonId);
                }
                else{
                    selectSql = GenerateSqlUtil.genSqlByPolygonIdAndVersionId(databaseName, associateEntry.getKey() + CommonConstant.HISTORY_SUFFIX,
                            associateEntry.getValue(), polygonId, versionCode);
                }

                List<Map<String, Object>> dataList = baseService.selectData(selectSql);
                if(dataList == null || dataList.size() == 0){
                    continue;
                }
                Map<String, Object> associateData = dataList.get(0);
                String primaryKey = TableOperationUtil.getPrimaryKey(associateTable);
                Map<String, Field> associateTableFields = new HashMap<>(associateTable.getFields());
                associateTableFields.remove(CommonConstant.FIX_FIELD_VERSION);
                associateTableFields = putDataToMap(associateData, associateTableFields);
                //----------20250730  对非根表加入camera处理逻辑------
                // 处理 camera 字段类型的媒体数据
                String cameraFieldName = TableOperationUtil.getCameraFieldName(associateTable);
                if (cameraFieldName != null && !cameraFieldName.equals("") && associateTableFields.containsKey(cameraFieldName)) {
                    String mediaTableNameInDb;
                    List<MultimediaItem> multiMediaItemList;
                    if (versionCode == maxVersionCodeInDB) {
                        mediaTableNameInDb = PostgreSqlUtil.buildTableNameString(databaseName, associateTable.getKey(), true, false);
                        multiMediaItemList = multimediaService.selectMultiMedia(mediaTableNameInDb, polygonId);
                    } else {
                        mediaTableNameInDb = PostgreSqlUtil.buildTableNameString(databaseName, associateTable.getKey(), true, true);
                        multiMediaItemList = multimediaService.selectHistoryMultiMedia(mediaTableNameInDb, polygonId, versionCode);
                    }
                    associateTableFields.get(cameraFieldName).setValue(multiMediaItemList);
                }
                //--------
                // 这里应该清理tableFields
                cleanTableForAndroid(associateTableFields);

                // ==== 新增几何字段处理逻辑 ====
                String geometryFieldName = CheckTableDataUtil.getGeometryFieldName(associateTable);
                if (geometryFieldName != null && associateTableFields.containsKey(geometryFieldName)) {
                    Field geoField = associateTableFields.get(geometryFieldName);
                    Object geoValue = geoField.getValue();
                    if (geoValue != null && geoValue instanceof String && !((String)geoValue).isEmpty()) {
                        geoField.setValue(ShapeTypeUtil.changeGeometryToArcGIS((String)geoValue));
                    }
                }
                // ==== 结束 ====

                associateTable.setFields(associateTableFields);
                Long associatePolygonId = Long.valueOf(associateData.get(primaryKey).toString());
                Map<String,String> childAssociateTableMap = CheckTableDataUtil.getAssociateField(associateTable, configString);
                Map<String,String> childCollectorTableMap = CheckTableDataUtil.getCollectionField(associateTable, configString);
                if(childAssociateTableMap.size() != 0 || childCollectorTableMap.size() != 0){
                    associateTable = recursiveChangeDataToTable(associateTable,databaseName,associatePolygonId, configString,
                            childAssociateTableMap,childCollectorTableMap,versionCode, maxVersionCodeInDB);
                }
                Field tempField = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(tableFields.get(associateEntry.getKey()), SerializerFeature.DisableCircularReferenceDetect)),
                        Field.class);
                tempField.setValue(associateTable.getFields());
                tableFields.remove(associateEntry.getKey());
                tableFields.put(associateEntry.getKey(), tempField);

            }
        }

        if(collectorTableMap.size() != 0){
            for(Map.Entry<String,String> collectorEntry : collectorTableMap.entrySet()){
                Table collectorTable = tables.get(collectorEntry.getKey());
                String selectSql;
                if(versionCode == maxVersionCodeInDB){
                    selectSql = GenerateSqlUtil.generateSelectSqlByField(databaseName, collectorEntry.getKey(),
                            collectorEntry.getValue(), polygonId);
                }
                else{
                    selectSql = GenerateSqlUtil.genSqlByPolygonIdAndVersionId(databaseName, collectorEntry.getKey() + CommonConstant.HISTORY_SUFFIX,
                            collectorEntry.getValue(), polygonId, versionCode);
                }

                List<Map<String, Object>> dataList = baseService.selectData(selectSql);
                if (dataList == null || dataList.size() == 0){
                    continue;
                }
                List<Map<String,Field>> result = new ArrayList<>();
                for(Map<String, Object> data : dataList){
                    Map<String, Field> collectorTableFields = new HashMap<>(collectorTable.getFields());
                    collectorTableFields.remove(CommonConstant.FIX_FIELD_VERSION);
                    collectorTableFields = putDataToMap(data, collectorTableFields);
                    //20250730  对非根表加入camera处理逻辑
                    String cameraFieldName = TableOperationUtil.getCameraFieldName(collectorTable);
                    if (cameraFieldName != null && !cameraFieldName.equals("") && collectorTableFields.containsKey(cameraFieldName)) {
                        String mediaTableNameInDb;
                        List<MultimediaItem> multiMediaItemList;
                        Long collectorPolygonId = Long.valueOf(data.get(TableOperationUtil.getPrimaryKey(collectorTable)).toString());
                        if (versionCode == maxVersionCodeInDB) {
                            mediaTableNameInDb = PostgreSqlUtil.buildTableNameString(databaseName, collectorTable.getKey(), true, false);
                            multiMediaItemList = multimediaService.selectMultiMedia(mediaTableNameInDb, collectorPolygonId);
                        } else {
                            mediaTableNameInDb = PostgreSqlUtil.buildTableNameString(databaseName, collectorTable.getKey(), true, true);
                            multiMediaItemList = multimediaService.selectHistoryMultiMedia(mediaTableNameInDb, collectorPolygonId, versionCode);
                        }
                        collectorTableFields.get(cameraFieldName).setValue(multiMediaItemList);
                    }
                    //-----------
                    // ==== 新增几何字段处理逻辑 ====
                    String geometryFieldName = CheckTableDataUtil.getGeometryFieldName(collectorTable);
                    if (geometryFieldName != null && collectorTableFields.containsKey(geometryFieldName)) {
                        Field geoField = collectorTableFields.get(geometryFieldName);
                        Object geoValue = geoField.getValue();
                        if (geoValue != null && geoValue instanceof String && !((String)geoValue).isEmpty()) {
                            geoField.setValue(ShapeTypeUtil.changeGeometryToArcGIS((String)geoValue));
                        }
                    }
                    // ==== 结束 ====
                    // 这里应该清理tableFields
                    cleanTableForAndroid(collectorTableFields);
                    result.add(collectorTableFields);
                }
                String primaryKey = TableOperationUtil.getPrimaryKey(collectorTable);
                Map<String,String> childAssociateTableMap = CheckTableDataUtil.getAssociateField(collectorTable, configString);
                Map<String,String> childCollectorTableMap = CheckTableDataUtil.getCollectionField(collectorTable, configString);
                for(Map<String, Object> data : dataList){
                    Long collectorPolygonId = Long.valueOf(data.get(primaryKey).toString());
                    if(childAssociateTableMap.size() != 0 || childCollectorTableMap.size() != 0){
                        collectorTable = recursiveChangeDataToTable(collectorTable,databaseName,collectorPolygonId, configString,
                                childAssociateTableMap,childCollectorTableMap,versionCode,
                                maxVersionCodeInDB);
                    }
                }
                tableFields.get(collectorEntry.getKey()).setValue(result);
                Field tempField = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(tableFields.get(collectorEntry.getKey()), SerializerFeature.DisableCircularReferenceDetect)),
                        Field.class);
                tempField.setValue(result);
                tableFields.remove(collectorEntry.getKey());
                tableFields.put(collectorEntry.getKey(), tempField);

            }
        }
        table.setFields(tableFields);
        return table;

    }

    /**
     * 将从数据库中获取的Map<String, Object> data，分别填入字段名对应的Field的value中
     */
    private Map<String,Field> putDataToMap(Map<String, Object> data, Map<String, Field> associateAndcollectorTableFields)
    {
        Map<String, Field> resultMap = new HashMap<>(associateAndcollectorTableFields);
        for(Map.Entry<String,Object> collectorDataEntry:data.entrySet())
        {
            for(Map.Entry<String,Field> entry:associateAndcollectorTableFields.entrySet())
            {
                if(collectorDataEntry.getKey().equals(entry.getKey()))
                {
                    Field tempField = JSON.toJavaObject(JSON.parseObject(JSON.toJSONString(entry.getValue(), SerializerFeature.DisableCircularReferenceDetect)),
                                                        Field.class);
                    tempField.setValue(collectorDataEntry.getValue());
                    resultMap.remove(entry.getKey());
                    resultMap.put(entry.getKey(), tempField);
                }
            }
        }
        return resultMap;
    }

    // 从多媒体文件路径中匹配采集人 ID 的正则表达式
    // 如 C:/CollectionSystem/MediaFile/task_23/user_1/20210913132531680.jpg 的匹配结果是 user_1
    private static final Pattern userIdPattern = Pattern.compile("user_\\d+");

    /**
     * 将获取的根表记录(既包括主表也包括历史表)数据添加到Map<String,Object>中，方便生成JsonString，将该部分操作
     * 封装成一个genResultMapByRootTableData方法，方便与上面的 getDataById 和 getDataByIdAndVersion 方法调用
     * @param table         Table类实例
     * @param rootTableData 根表记录Map<String, Object>
     * @param task          Task类实例
     */
    private Map<String,Object> genResultMapByRootTableData(Table table, Map<String, Object> rootTableData, Task task, boolean isHistory) throws Exception
    {
        Map<String,Object> result = new HashMap<>();
        Map<String, Field> fields = table.getFields();
        String geometryFieldName = CheckTableDataUtil.getGeometryFieldName(table);
        String primaryKey = TableOperationUtil.getPrimaryKey(table);

        // 将数据库中查询到的属性信息添加到result中
        for (Map.Entry<String, Object> entry:rootTableData.entrySet())
        {
            String entryKey = entry.getKey();
            Object entryValue = entry.getValue();
            if (!entryKey.equals(CommonConstant.FIX_FIELD_VERSION)
                    && !entryKey.equals(CommonConstant.FIX_FIELD_CREATE_TIME)
                    && !entryKey.equals(CommonConstant.FIX_FIELD_UPDATE_TIME)
                    && !entryKey.equals(CommonConstant.FIX_FIELD_REASON)
                    && !entryKey.equals(geometryFieldName)
                    && !entryKey.equals(CommonConstant.GEOMETRY)){
                switch (entryKey){
                    case CommonConstant.FIX_FIELD_COLLECTOR:{
                        Integer collectorId = Integer.valueOf(rootTableData.get(CommonConstant.FIX_FIELD_COLLECTOR).toString());
                        if (userService.findById(collectorId).isPresent()){
                            result.put("采集员" , userService.findById(collectorId).get().getRealName());
                        }
                        else{
                            result.put("采集员", "无");
                        }
                        break;
                    }
                    case CommonConstant.FIX_FIELD_REVIEWER:{
                        Integer reviewerId = Integer.valueOf(entryValue.toString());
                        if (reviewerId == -1){
                            result.put("巡查员" , "无");
                        }
                        else{
                            User user = userService.findById(reviewerId).get();
                            result.put("巡查员" , user.getRealName());
                        }
                        break;
                    }
                    default:
                        Field field = fields.get(entryKey);
                        Map<String,String> selectKeyValueMap = OtherUtil.getSelectKeyValueMap(xmlEnityService.getXmlEnityById(task.getXmlId()).getFilePath(),
                                                                                              table.getKey(), field.getKey());
                        String key;
                        if (field.getName() != null && !field.getName().equals("")){
                            key = field.getName();
                        }
                        else{
                            key = field.getKey();
                        }
                        // 针对字段的type为PHOTO类型需要特殊处理
                        if (field.getType() != null && field.getType().equals(CommonConstant.PHOTO)
                                && entryValue != null && ! entryValue.toString().equals(""))
                        {
                            String fileName = entryValue.toString().substring(entryValue.toString().lastIndexOf('/') + 1);
                            Integer collectorId = Integer.valueOf(rootTableData.get(CommonConstant.FIX_FIELD_COLLECTOR).toString());
                            result.put(key, CommonConstant.GET_PICTURE_PREFIX + task.getId() + "/" + collectorId + "/" + fileName);
                            continue;
                        }
                        // 针对status字段，需要特殊处理
                        if (field.getKey().equals(CommonConstant.FIX_FIELD_STATUS)){
                            int status = Integer.valueOf(entryValue.toString());
                            result.put("数据状态",OtherUtil.getStatusMeaning(status));
                            if(status == -1){
                                result.put("审核未通过原因",rootTableData.get(CommonConstant.FIX_FIELD_REASON));
                            }
                            continue;
                        }
                        // 针对primaryKey字段
                        if (field.getKey().equals(primaryKey))
                        {
                            result.put("id",entryValue);
                            continue;
                        }
                        if (selectKeyValueMap != null && selectKeyValueMap.size() != 0 && field.getResultType() != null
                                && field.getResultType().equals("key"))
                        {
                            // 因为CheckBox和CheckView存在多选的情况，所以得把每一对情况都生成Map
                            List<Map<String,String>> keyValueMapList = new ArrayList<>();
                            for (String value : entry.getValue().toString().split(","))
                            {
                                Map<String,String> keyValueMap = new HashMap<>();
                                keyValueMap.put("key",value.trim());
                                keyValueMap.put("value",selectKeyValueMap.get(value.trim()));
                                keyValueMapList.add(keyValueMap);
                            }
                            result.put(key,JSON.toJSONString(keyValueMapList));
                        }
                        else if (selectKeyValueMap != null && selectKeyValueMap.size() !=0 && field.getResultType() != null
                                && field.getResultType().equals("value"))
                        {
                            // 因为CheckBox和CheckView存在多选的情况，所以得把每一对情况都生成Map
                            List<Map<String,String>> keyValueMapList = new ArrayList<>();
                            for (String value : entry.getValue().toString().split(","))
                            {
                                Map<String,String> keyValueMap = new HashMap<>();
                                keyValueMap.put("key", OtherUtil.getKeyByValue(selectKeyValueMap, value.trim()));
                                keyValueMap.put("value",value.trim());
                                keyValueMapList.add(keyValueMap);
                            }
                            result.put(key,JSON.toJSONString(keyValueMapList));
                        }
                        else
                        {
                            if (field.getAutoDate() != null && !field.getAutoDate().equals("")
                                    && field.getDbType().equals(CommonConstant.DATE))
                            {
                                SimpleDateFormat simpleDateFormat = new SimpleDateFormat(field.getAutoDate());
                                result.put(key, simpleDateFormat.format(entry.getValue()));
                            }
                            else if ((field.getAutoDate() == null || field.getAutoDate().equals(""))
                                    && field.getDbType().equals(CommonConstant.DATE))
                            {
                                result.put(key, new SimpleDateFormat(CommonConstant.DATE_FORMAT_STRING).format(entry.getValue()));
                            }
                            else
                            {
                                result.put(key,entry.getValue());
                            }
                        }
                        break;
                }
            }
        }

        // 将多媒体信息添加result中
        String mediatableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), table.getKey(), true, isHistory);
        List<String> mediaFileUrlList = new ArrayList<>();
        List<MultimediaItem> multimediaItemList = isHistory ?
                multimediaService.selectHistoryMultiMedia(mediatableNameInDb, Long.valueOf(rootTableData.get(primaryKey).toString()), (int) rootTableData.get(CommonConstant.FIX_FIELD_VERSION))
                : multimediaService.selectMultiMedia(mediatableNameInDb, Long.valueOf(rootTableData.get(primaryKey).toString()));
        if (multimediaItemList == null)
        {
            result.put("mediaFileURLs","");
        }
        else
        {
            for (MultimediaItem multimediaItem:multimediaItemList)
            {
                String fileName = multimediaItem.getFile();
                String mediaPath = multimediaItem.getMediaPath();
                Matcher matcher = userIdPattern.matcher(mediaPath);
                if (matcher.find()) {
                    String userId = mediaPath.substring(matcher.start() + 5, matcher.end());
                    if (fileName.endsWith(".jpg") || fileName.endsWith(".png") || fileName.endsWith(".gif"))
                    {

                        mediaFileUrlList.add(CommonConstant.GET_PICTURE_PREFIX + task.getId() + "/" + userId + "/" + fileName);
                    }
                    else
                    {
                        mediaFileUrlList.add(CommonConstant.GET_VIDEO_PREFIX + task.getId() + "/" + userId + "/" + fileName);
                    }
                }
            }
            result.put("mediaFileURLs",mediaFileUrlList);
        }
        return result;
    }
    /**
     * 将获取的非根表记录数据添加到 Map<String, Object> 中，方便生成 JsonString。
     * 相比根表，非根表中通常不包含 collector、reviewer、status 等字段。
     *
     * @param table        Table类实例
     * @param subTableData 非根表记录 Map<String, Object>
     * @param task         Task类实例
     */
//    private Map<String, Object> genResultMapBySubTableData(Table table, Map<String, Object> subTableData, Task task) throws Exception {
//        Map<String, Object> result = new HashMap<>();
//        Map<String, Field> fields = table.getFields();
//        String geometryFieldName = CheckTableDataUtil.getGeometryFieldName(table); // ⚠️ 可能为 null
//        String primaryKey = TableOperationUtil.getPrimaryKey(table);
//
//        for (Map.Entry<String, Object> entry : subTableData.entrySet()) {
//            String entryKey = entry.getKey();
//            Object entryValue = entry.getValue();
//
//            // ⚠️ 跳过 geometry 字段（如果存在定义）
//            if ((geometryFieldName != null && entryKey.equals(geometryFieldName))
//                    || entryKey.equals(CommonConstant.GEOMETRY)) {
//                continue;
//            }
//
//            Field field = fields.get(entryKey);
//            if (field == null) continue; // 跳过未定义字段
//
//            String key = (field.getName() != null && !field.getName().isEmpty()) ? field.getName() : field.getKey();
//
//            // PHOTO 类型字段处理
//            if (CommonConstant.PHOTO.equals(field.getType())
//                    && entryValue != null && !entryValue.toString().isEmpty()) {
//                String fileName = entryValue.toString().substring(entryValue.toString().lastIndexOf('/') + 1);
//                result.put(key, CommonConstant.GET_PICTURE_PREFIX + task.getId() + "/unknown/" + fileName);
//                continue;
//            }
//
//            // 字典值映射处理
//            Map<String, String> selectKeyValueMap = OtherUtil.getSelectKeyValueMap(
//                    xmlEnityService.getXmlEnityById(task.getXmlId()).getFilePath(),
//                    table.getKey(), field.getKey());
//
//            if (selectKeyValueMap != null && !selectKeyValueMap.isEmpty() && field.getResultType() != null) {
//                List<Map<String, String>> keyValueMapList = new ArrayList<>();
//                for (String value : entryValue.toString().split(",")) {
//                    Map<String, String> map = new HashMap<>();
//                    if ("key".equals(field.getResultType())) {
//                        map.put("key", value.trim());
//                        map.put("value", selectKeyValueMap.get(value.trim()));
//                    } else if ("value".equals(field.getResultType())) {
//                        map.put("key", OtherUtil.getKeyByValue(selectKeyValueMap, value.trim()));
//                        map.put("value", value.trim());
//                    }
//                    keyValueMapList.add(map);
//                }
//                result.put(key, JSON.toJSONString(keyValueMapList));
//            } else {
//                // 时间字段处理
//                if (CommonConstant.DATE.equals(field.getDbType())) {
//                    if (field.getAutoDate() != null && !field.getAutoDate().isEmpty()) {
//                        result.put(key, new SimpleDateFormat(field.getAutoDate()).format(entryValue));
//                    } else {
//                        result.put(key, new SimpleDateFormat(CommonConstant.DATE_FORMAT_STRING).format(entryValue));
//                    }
//                } else {
//                    result.put(key, entryValue);
//                }
//            }
//
//            // 主键字段显式放置 "id" 字段
//            if (primaryKey.equals(field.getKey())) {
//                result.put("id", entryValue);
//            }
//        }
//
//        // 添加多媒体资源（如果有）
//        String mediaTableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), table.getKey(), true, false);
//        List<MultimediaItem> multimediaItemList = multimediaService.selectMultiMedia(
//                mediaTableNameInDb, Long.valueOf(subTableData.get(primaryKey).toString()));
//
//        List<String> mediaFileUrlList = new ArrayList<>();
//        if (multimediaItemList != null) {
//            for (MultimediaItem item : multimediaItemList) {
//                String fileName = item.getFile();
//                String mediaPath = item.getMediaPath();
//                Matcher matcher = userIdPattern.matcher(mediaPath);
//                String userId = matcher.find() ? mediaPath.substring(matcher.start() + 5, matcher.end()) : "unknown";
//
//                String prefix = (fileName.endsWith(".jpg") || fileName.endsWith(".png") || fileName.endsWith(".gif"))
//                        ? CommonConstant.GET_PICTURE_PREFIX
//                        : CommonConstant.GET_VIDEO_PREFIX;
//                mediaFileUrlList.add(prefix + task.getId() + "/" + userId + "/" + fileName);
//                System.out.println("mediaFileUrlList: " + mediaFileUrlList);
//            }
//        }
//        result.put("mediaFileURLs", mediaFileUrlList);
//        return result;
//    }
    private Map<String, Object> genResultMapBySubTableData(Table table, Map<String, Object> subTableData, Task task) throws Exception {
        Map<String, Object> result = new HashMap<>();
        Map<String, Field> fields = table.getFields();
        String geometryFieldName = CheckTableDataUtil.getGeometryFieldName(table); // ⚠️ 可能为 null
        String primaryKey = TableOperationUtil.getPrimaryKey(table);

        for (Map.Entry<String, Object> entry : subTableData.entrySet()) {
            String entryKey = entry.getKey();
            Object entryValue = entry.getValue();

            // ⚠️ 跳过 geometry 字段（如果存在定义）
            if ((geometryFieldName != null && entryKey.equals(geometryFieldName))
                    || entryKey.equals(CommonConstant.GEOMETRY)) {
                continue;
            }

            Field field = fields.get(entryKey);
            if (field == null) continue; // 跳过未定义字段

            String key = (field.getName() != null && !field.getName().isEmpty()) ? field.getName() : field.getKey();

            // PHOTO 类型字段处理（photo 字段只展示一张图）
            if (CommonConstant.PHOTO.equals(field.getType())
                    && entryValue != null && !entryValue.toString().isEmpty()) {
                String fileName = entryValue.toString().substring(entryValue.toString().lastIndexOf('/') + 1);
                result.put(key, CommonConstant.GET_PICTURE_PREFIX + task.getId() + "/unknown/" + fileName);
                continue;
            }

            // 字典值映射处理
            Map<String, String> selectKeyValueMap = OtherUtil.getSelectKeyValueMap(
                    xmlEnityService.getXmlEnityById(task.getXmlId()).getFilePath(),
                    table.getKey(), field.getKey());
            if (selectKeyValueMap != null && !selectKeyValueMap.isEmpty() && field.getResultType() != null) {
                List<Map<String, String>> keyValueMapList = new ArrayList<>();
                for (String value : entryValue.toString().split(",")) {
                    Map<String, String> map = new HashMap<>();
                    if ("key".equals(field.getResultType())) {
                        map.put("key", value.trim());
                        map.put("value", selectKeyValueMap.get(value.trim()));
                    } else if ("value".equals(field.getResultType())) {
                        map.put("key", OtherUtil.getKeyByValue(selectKeyValueMap, value.trim()));
                        map.put("value", value.trim());
                    }
                    keyValueMapList.add(map);
                }
                result.put(key, JSON.toJSONString(keyValueMapList));
            } else {
                // 时间字段处理
                if (CommonConstant.DATE.equals(field.getDbType())) {
                    if (field.getAutoDate() != null && !field.getAutoDate().isEmpty()) {
                        result.put(key, new SimpleDateFormat(field.getAutoDate()).format(entryValue));
                    } else {
                        result.put(key, new SimpleDateFormat(CommonConstant.DATE_FORMAT_STRING).format(entryValue));
                    }
                } else {
                    result.put(key, entryValue);
                }
            }

            // 主键字段显式放置 "id" 字段
            if (primaryKey.equals(field.getKey())) {
                result.put("id", entryValue);
            }
        }

        List<String> mediaFileUrlList = new ArrayList<>();
        Config config = JSON.parseObject(task.getConfig(), Config.class);
        boolean isRootTable = config.getRootTables().containsKey(table.getKey());

        if (isRootTable) {
            String mediaTableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), table.getKey(), true, false);
            try {
                List<MultimediaItem> multimediaItemList = multimediaService.selectMultiMedia(
                        mediaTableNameInDb, Long.valueOf(subTableData.get(primaryKey).toString()));

                if (multimediaItemList != null && !multimediaItemList.isEmpty()) {
                    for (MultimediaItem item : multimediaItemList) {
                        String fileName = item.getFile();
                        String mediaPath = item.getMediaPath();
                        Matcher matcher = userIdPattern.matcher(mediaPath);
                        String userId = matcher.find() ? mediaPath.substring(matcher.start() + 5, matcher.end()) : "unknown";

                        String prefix = (fileName.endsWith(".jpg") || fileName.endsWith(".png") || fileName.endsWith(".gif"))
                                ? CommonConstant.GET_PICTURE_PREFIX
                                : CommonConstant.GET_VIDEO_PREFIX;
                        mediaFileUrlList.add(prefix + task.getId() + "/" + userId + "/" + fileName);
                    }
                }
            } catch (Exception e) {
                log.warn("查询根表多媒体失败：" + e.getMessage());
            }
        } else {
            // fallback：从 photo 字段构造 media URL（非根表情况）
            Object photoObj = subTableData.get("photo");
            if (photoObj != null && !photoObj.toString().trim().isEmpty()) {
                String fileName = photoObj.toString().trim();
                String prefix = (fileName.endsWith(".jpg") || fileName.endsWith(".png") || fileName.endsWith(".gif"))
                        ? CommonConstant.GET_PICTURE_PREFIX
                        : CommonConstant.GET_VIDEO_PREFIX;
                mediaFileUrlList.add(prefix + task.getId() + "/unknown/" + fileName);
            }
        }


        result.put("mediaFileURLs", mediaFileUrlList);
        return result;
    }

    /**
     * 将获取的根表记录转换成一个FeatureList返回给前端，将这些操作封装成一个方法，
     * 供getDataByRangeIntersection() 和 getAllDataForTaskIdAndTableName()方法调用
     * @param task                  task实例
     * @param tableName             根表名
     * @param rootTableDataList     查询到的根表数据，注意该List != null && List.size != 0
     */
    private List<Feature> changeRootTableDataToFeatureList(Task task, String tableName, String geometryFieldName,
                                                           List<Map<String, Object>> rootTableDataList, boolean addSelectOrderValue,
                                                           Integer destTaskId, String destTableName)
    {
        Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
        Table table = config.getTables().get(tableName);
        String primaryKey = TableOperationUtil.getPrimaryKey(table);
        String uploadNameFieldName = TableOperationUtil.getUploadNameFieldName(table);
        List<Feature> featureList = new ArrayList<>();

        for (Map<String, Object> rootTableData : rootTableDataList)
        {
            Feature feature = new Feature();
            feature.setType(CommonConstant.FEATURE);
            feature.setGeometry(JSON.toJavaObject(JSON.parseObject(rootTableData.get(geometryFieldName).toString()),
                                                  GeometryType.class));
            Map<String,String> propertiesMap = new HashMap<>();
            propertiesMap.put("id",rootTableData.get(primaryKey).toString());
            if (rootTableData.containsKey(CommonConstant.FIX_FIELD_REVIEWER) && (Integer)rootTableData.get(CommonConstant.FIX_FIELD_REVIEWER) == -1)
            {
                propertiesMap.put(CommonConstant.FIX_FIELD_REVIEWER, "无审核人员");
            }
            else if (rootTableData.containsKey(CommonConstant.FIX_FIELD_REVIEWER) && (Integer)rootTableData.get(CommonConstant.FIX_FIELD_REVIEWER) != -1)
            {
                propertiesMap.put(CommonConstant.FIX_FIELD_REVIEWER, userService.findById(Integer.valueOf(rootTableData.get(CommonConstant.FIX_FIELD_REVIEWER).toString())).get().getRealName());
            }
            // 另外添加selectOrder属性，判断该数据是否被抽查过，若未被抽查过，赋予selectOrder为0，否则赋予对应值
            if (addSelectOrderValue)
            {
                List<TaskSelectId> taskSelectIdList = taskSelectIdService.getTaskSelectIdByTaskIdAndTableName(task.getId(), tableName,destTaskId,destTableName);
                propertiesMap.put("selectOrder", getSelectOrderById(taskSelectIdList, rootTableData.get(primaryKey).toString()));
                Integer maxSelectOrder = taskSelectIdService.getMaxSelectOrder(task.getId(), tableName, destTaskId, destTableName);
                propertiesMap.put("selectNum", maxSelectOrder == null ? "0" : maxSelectOrder.toString());
            }
            // 添加显示字段
            if (rootTableData.containsKey(uploadNameFieldName)) {
                if(CommonConstant.FIX_FIELD_COLLECTOR.equals(uploadNameFieldName)){
                    // 把id转成名称
                    Optional<User> opUser = userService.findById(Integer.parseInt(rootTableData.get(CommonConstant.FIX_FIELD_COLLECTOR).toString()));
                    propertiesMap.put("_upload_name", opUser.map(User::getUsername).orElse(null));
                }else{
                    propertiesMap.put("_upload_name", rootTableData.get(uploadNameFieldName).toString());
                }
            }
            feature.setProperties(propertiesMap);
            featureList.add(feature);
        }
        return featureList;
    }

    /**
     * 判断primaryKey值是否存在于TaskSelectId的selectId属性中，若存在返回对应的selectOrder
     */
    private String getSelectOrderById(List<TaskSelectId> taskSelectIdList, String primaryKey)
    {
        for (TaskSelectId taskSelectId : taskSelectIdList)
        {
            if (taskSelectId.getSelectId().contains(primaryKey))
            {
                return taskSelectId.getSelectOrder().toString();
            }
        }
        return "0";
    }
    //20250730  lxy
    @RequestMapping(value = "getSubDataByRangeIntersection", produces = "text/html;charset=UTF-8")
    public String getSubDataByRangeIntersection(Integer taskId, String tableName, Integer parentId, Double longitudeMin, Double latitudeMin,
                                                Double longitudeMax, Double latitudeMax){


        Task task = taskService.getTaskById(taskId);
        Table table = JSON.toJavaObject(JSON.parseObject(task.getConfig()),Config.class).getTables().get(tableName);
        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);

        String primaryKeyField = TableOperationUtil.getPrimaryKey(table);
        String geomField = CheckTableDataUtil.getGeometryFieldName(table);
        String uploadNameField = TableOperationUtil.getUploadNameFieldName(table);

        // 构建额外的parentID条件
        String parentIdCondition = parentId != null
                ? " AND \"parentID\" = '" + parentId + "'"
                : "";

        String selectSql = String.format(
                "SELECT %s, %s FROM %s WHERE ST_Intersects(ST_MakeEnvelope(%f, %f, %f, %f, 4490), st_setsrid(ST_GeomFromGeoJSON(%s), 4490))" + parentIdCondition,
                PostgreSqlUtil.transformString(primaryKeyField),
                PostgreSqlUtil.transformString(geomField),
                tableNameInDb,
                longitudeMin, latitudeMin, longitudeMax, latitudeMax,
                PostgreSqlUtil.transformString(geomField)
        );

//        String selectSql = MessageFormat.format(
//                SqlStringConstant.SELECT_SQL_BY_RANGE_INTERSECTION + parentIdCondition, // 追加条件
//                tableNameInDb,
//                PostgreSqlUtil.transformString(TableOperationUtil.getPrimaryKey(table)),
//                PostgreSqlUtil.transformString(CheckTableDataUtil.getGeometryFieldName(table)),
//                PostgreSqlUtil.transformString(TableOperationUtil.getUploadNameFieldName(table)),
//                longitudeMin,
//                latitudeMin,
//                longitudeMax,
//                latitudeMax
//        );

        List<Map<String,Object>> rootTableDataList = baseService.selectData(selectSql);
        if (rootTableDataList == null || rootTableDataList.size() == 0)
        {
            return ResultMessage.success(null).toString();
        }
        else{
            List<Feature> featureList = changeRootTableDataToFeatureList(task, tableName, CheckTableDataUtil.getGeometryFieldName(table),
                    rootTableDataList, false,null,null);
            return ResultMessage.success(featureList).toStringByDisableCircularReference();
        }
    }

    /**
     * 获取某任务下某个表中所有数据的ID字段唯一值
     * @param taskId     任务ID
     * @param tableName  表名
     * @param userId     用户ID
     * @return ID字段的所有唯一值列表
     */
    @RequestMapping(value = "getDistinctIds", produces = "text/html;charset=UTF-8")
    public String getDistinctIds(Integer taskId, String tableName, Integer userId) {
        // 参数校验
        if (taskId == null || tableName == null || userId == null) {
            return ResultMessage.failed("参数不能为空").toString();
        }

        try {
            // 获取任务信息
            Task task = taskService.getTaskById(taskId);
            if (task == null) {
                return ResultMessage.failed("当前任务已删除!").toString();
            }

            // 判断该用户是否在对应的任务中
            if (!OtherUtil.isUserInTask(task, userId, taskUserRoleService)) {
                return ResultMessage.failed("您不在该任务中!").toString();
            }

            // 构建表名
            String dbTableName = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);

            // 获取主键字段名
            Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
            Map<String, Table> tablesMap = config.getTables();
            Table table = tablesMap.get(tableName);

            if (table == null) {
                return ResultMessage.failed("表不存在").toString();
            }

            String primaryKey = TableOperationUtil.getPrimaryKey(table);
            if (primaryKey == null || primaryKey.isEmpty()) {
                return ResultMessage.failed("无法获取表的主键字段").toString();
            }

            // 构建查询SQL
            String selectDistinctIdsSql = MessageFormat.format(
                    "SELECT DISTINCT {0} FROM {1} ORDER BY {0}",
                    PostgreSqlUtil.transformString(primaryKey),
                    dbTableName
            );

            // 执行查询
            List<Map<String, Object>> resultData = baseService.selectData(selectDistinctIdsSql);

            // 提取ID值
            List<Long> idList = new ArrayList<>();
            if (resultData != null && !resultData.isEmpty()) {
                for (Map<String, Object> row : resultData) {
                    Object idValue = row.get(primaryKey);
                    if (idValue != null) {
                        if (idValue instanceof Number) {
                            idList.add(((Number) idValue).longValue());
                        } else {
                            try {
                                idList.add(Long.parseLong(idValue.toString()));
                            } catch (NumberFormatException e) {
                                // 忽略无法转换为Long的值
                            }
                        }
                    }
                }
            }

            return ResultMessage.success(idList).toString();
        } catch (Exception e) {
            log.error("获取ID唯一值列表失败", e);
            return ResultMessage.failed("获取ID唯一值列表失败: " + e.getMessage()).toString();
        }
    }
}
