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

import cn.edu.whu.boot.collection.service.ExportService;
import cn.edu.whu.boot.collection.service.IBaseService;
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.OtherUtil;
import cn.edu.whu.boot.common.utils.collection.PostgreSqlUtil;
import cn.edu.whu.boot.common.utils.collection.StoreMediaFileUtil;
import cn.edu.whu.boot.common.utils.collection.TableOperationUtil;
import cn.edu.whu.boot.common.utils.xml.CheckTableDataUtil;
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.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.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.gdal.ogr.Geometry;
import org.geotools.data.DataUtilities;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.Transaction;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.locationtech.jts.geom.*;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import org.gdal.ogr.*;
import org.gdal.osr.SpatialReference;

import org.gdal.gdal.gdal;
import org.gdal.ogr.ogr;
/**
 * 导出数据的接口，对应“下载数据按钮”
 */
@RestController
@RequestMapping("export")
public class ExportController{
    private static final Logger logger = LoggerFactory.getLogger(ExportController.class);

    private final ITaskService taskService;
    private final IBaseService baseService;
    private final UserService userService;
    private final ExportService exportService;

    @Autowired
    public ExportController(ITaskService taskService, IBaseService baseService, UserService userService, ExportService exportService){
        this.taskService = taskService;
        this.baseService = baseService;
        this.userService = userService;
        this.exportService = exportService;
    }
@RequestMapping(value = "taskTableDataExport", produces = "text/html;charset=UTF-8")
public String taskTableDataExport(Integer taskId, String tableName,
                                  boolean isHighVersion, HttpServletResponse response) throws IOException {
    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_ALLDATA_SQL, tableNameInDb);
    List<Map<String, Object>> tableDataList = baseService.selectData(selectSql);
    // ✅ 空数据判断，避免后续导出报错
    if (CollectionUtils.isEmpty(tableDataList)) {
        return ResultMessage.failed("数据为空，无法导出").toString();
    }

    // 导出文件夹准备
    Map<Integer, String> idToRealName = new HashMap<>();
    String exportDir = CommonConstant.TEMP_FILE_PATHNAME + "/" + System.currentTimeMillis();
    File exportDirFile = new File(exportDir);
    if (!exportDirFile.exists()) {
        exportDirFile.mkdirs();
    }

    /// ✅ 判断是否有合法几何数据（Java 8 写法，字段名写死为 "shape"）
    boolean hasGeometryData = false;
    for (Map<String, Object> row : tableDataList) {
        Object geom = row.get("shape");  // 写死字段名为 "shape"
        if (geom != null && !geom.toString().trim().isEmpty()) {
            hasGeometryData = true;
            break;
        }
    }
    if (CollectionUtils.isNotEmpty(tableDataList)) {
        String shpFileNamePrefix = String.valueOf(System.currentTimeMillis());
        File shpFileNamePrefixDir = new File(CommonConstant.TEMP_FILE_PATHNAME + "/" + shpFileNamePrefix);
        if (!shpFileNamePrefixDir.exists()) {
            shpFileNamePrefixDir.mkdirs();
        }

        if (hasGeometryData) {
            createShpByGeometryType(table, tableDataList, CommonConstant.POINT, shpFileNamePrefix, isHighVersion, idToRealName);
            createShpByGeometryType(table, tableDataList, CommonConstant.LINESTRING, shpFileNamePrefix, isHighVersion, idToRealName);
            createShpByGeometryType(table, tableDataList, CommonConstant.POLYGON, shpFileNamePrefix, isHighVersion, idToRealName);
            createShpByGeometryType(table, tableDataList, CommonConstant.MULTIPOLYGON, shpFileNamePrefix, isHighVersion, idToRealName);
        } else {
            // ✅ 改为导出 Excel
            exportExcelFile(table, tableDataList, exportDir, idToRealName);
        }
    }

    // 导出 table_media 表（如果存在）
    String tableNameMedia = tableName + "_media";
    exportTableMedia(task.getDatabaseName(), tableNameMedia, exportDir);

    // 压缩所有文件
    String zipFilePath = StoreMediaFileUtil.zip(CommonConstant.TEMP_FILE_PATHNAME, Collections.singletonList(exportDir), null);
    File zipFile = new File(zipFilePath);

    // 设置响应头并下载 zip 文件
    response.setContentType("application/x-zip-compressed");
    response.addHeader("Content-Disposition",
            "attachment;fileName=" + new String(task.getTaskName().getBytes(), "iso-8859-1") + ".zip");
    String result = OtherUtil.uploadFileByResponse(zipFile, response);

    // 清理临时文件
    FileUtils.deleteDirectory(exportDirFile);
    zipFile.delete();

    if (CommonConstant.FAILED.equals(result)) {
        return ResultMessage.failed(null).toString();
    }
    return ResultMessage.success(null).toString();
}


    // 直接从数据库查询字段和数据，导出 Excel
    private void exportTableMedia(String databaseName, String tableNameMedia, String exportDir) throws IOException {
        List<String> fieldNames = baseService.getTableColumns(databaseName,tableNameMedia);
        if (fieldNames.isEmpty()) {
            System.out.println("表 " + tableNameMedia + " 不存在或无字段！");
            return;
        }

        String selectSql = "SELECT * FROM \"" + databaseName + "\".\"" + tableNameMedia + "\"";
        List<Map<String, Object>> dataList = baseService.selectData(selectSql);

        if (dataList == null || dataList.isEmpty()) {
            System.out.println("表 " + tableNameMedia + " 查询结果为空！");
            return;
        }

        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");
        Row firstRow = sheet.createRow(0);
        for (int i = 0; i < fieldNames.size(); i++) {
            firstRow.createCell(i).setCellValue(fieldNames.get(i));
        }

        int rowNum = 1;
        for (Map<String, Object> rowData : dataList) {
            Row row = sheet.createRow(rowNum++);
            for (int i = 0; i < fieldNames.size(); i++) {
                String fieldName = fieldNames.get(i);
                row.createCell(i).setCellValue(rowData.getOrDefault(fieldName, "").toString());
            }
        }

        File excelFile = new File(exportDir, tableNameMedia + ".xlsx");
        try (FileOutputStream fos = new FileOutputStream(excelFile)) {
            workbook.write(fos);
        }
    }
//@RequestMapping(value = "taskGdbExport", produces = "text/html;charset=UTF-8")
//public String taskGdbExport(Integer taskId, HttpServletResponse response) throws IOException {
//    // ✅ 初始化 GDAL
//    ogr.RegisterAll();
//    gdal.AllRegister();
//    // 支持中文路径和中文字段名
//    gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
//    gdal.SetConfigOption("SHAPE_ENCODING", "");
//
//    Task task = taskService.getTaskById(taskId);
//    Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
//    Map<String, Table> tableMap = config.getTables();
//
//    // ✅ 表名 → 中文图层名映射
//    Map<String, String> tableNameAliasMap = new HashMap<>();
//    tableNameAliasMap.put("roottable1", "小班表");
//    tableNameAliasMap.put("t1sub1", "样地表");
//    tableNameAliasMap.put("t1sub2", "样木表");
//    tableNameAliasMap.put("t1sub3", "没有");
//    tableNameAliasMap.put("t1sub4", "幼树样方");
//    tableNameAliasMap.put("t1sub5", "幼树表");
//    tableNameAliasMap.put("t1sub6", "下木样方");
//    tableNameAliasMap.put("t1sub7", "下木表");
//    tableNameAliasMap.put("t1sub8", "未成林样方");
//    tableNameAliasMap.put("t1sub9", "未成林表");
//    tableNameAliasMap.put("t1sub10", "生物多样性");
//    tableNameAliasMap.put("t1sub12", "经济林样方");
//    tableNameAliasMap.put("t1sub13", "经济树种表");
//    tableNameAliasMap.put("t1sub201", "灌木样方");
//    tableNameAliasMap.put("t1sub21", "灌木调查表");
//    tableNameAliasMap.put("t1sub202", "藤本样方");
//    tableNameAliasMap.put("t1sub22", "藤本调查表");
//    tableNameAliasMap.put("t1sub203", "草本样方");
//    tableNameAliasMap.put("t1sub23", "草本调查表");
//    tableNameAliasMap.put("t1sub204", "地被样方");
//    tableNameAliasMap.put("t1sub24", "地被调查表");
//    tableNameAliasMap.put("t1sub25", "目测项目表");
//    tableNameAliasMap.put("t1sub251", "目测单项表");
//    tableNameAliasMap.put("roottable3", "散生木表");
//    tableNameAliasMap.put("t3sub", "散生单木表");
//    tableNameAliasMap.put("roottable4", "四旁树表");
//    tableNameAliasMap.put("t4sub", "四旁树单木表");
//
//    // ✅ 临时导出路径
//    String exportDir = CommonConstant.TEMP_FILE_PATHNAME + "/" + System.currentTimeMillis();
//    File exportDirFile = new File(exportDir);
//    exportDirFile.mkdirs();
//
//    String gdbName = task.getTaskName() + ".gdb";
//    File gdbDir = new File(exportDirFile, gdbName);
//    if (gdbDir.exists()) FileUtils.deleteDirectory(gdbDir);
//
//    // ✅ 创建 FileGDB 数据源
//    Driver driver = ogr.GetDriverByName("FileGDB");
//    if (driver == null) {
//        throw new RuntimeException("未找到 FileGDB 驱动，请确认 GDAL 已正确安装并支持 FileGDB。");
//    }
//    DataSource dataSource = driver.CreateDataSource(gdbDir.getAbsolutePath());
//    if (dataSource == null) {
//        throw new RuntimeException("创建 FileGDB 数据源失败：" + gdbDir.getAbsolutePath());
//    }
//    // ✅ 遍历每个表
//    for (Map.Entry<String, Table> entry : tableMap.entrySet()) {
//        String tableName = entry.getKey();
//        Table table = entry.getValue();
//        String layerName = tableNameAliasMap.getOrDefault(tableName, tableName);
//        String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);
//        String selectSql = MessageFormat.format(SqlStringConstant.SELECT_ALLDATA_SQL, tableNameInDb);
//        List<Map<String, Object>> tableDataList = baseService.selectData(selectSql);
//
//        if (tableDataList == null || tableDataList.isEmpty()) {
//            System.out.println("⚠️ 表数据为空：" + tableName);
//            continue; // 跳过空表
//        }
//
//        boolean hasGeometry = tableDataList.stream().anyMatch(row -> {
//            Object geom = row.get("shape");
//            return geom != null && !geom.toString().trim().isEmpty();
//        });
//
//        if (hasGeometry) {
//            addGeometryLayerToGdb(dataSource, table, layerName, tableDataList);
//        } else {
//            addTableToGdb(dataSource, table, layerName, tableDataList);
//        }
//    }
//    dataSource.delete(); // ✅ 保存并关闭
//    // ✅ 压缩 GDB 文件夹为 ZIP
//    String zipFilePath = StoreMediaFileUtil.zip(exportDir, Collections.singletonList(gdbDir.getAbsolutePath()), null);
//    File zipFile = new File(zipFilePath);
//
//    // ✅ 下载响应
//    response.setContentType("application/x-zip-compressed");
//    response.addHeader("Content-Disposition",
//            "attachment;fileName=" + new String(task.getTaskName().getBytes(StandardCharsets.UTF_8), "iso-8859-1") + ".zip");
//    String result = OtherUtil.uploadFileByResponse(zipFile, response);
//
//    // ✅ 清理临时文件
//    FileUtils.deleteDirectory(exportDirFile);
//    zipFile.delete();
//
//    if (CommonConstant.FAILED.equals(result)) {
//        return ResultMessage.failed(null).toString();
//    }
//    return ResultMessage.success(null).toString();
//}
    /**
     * 下载数据接口，导出单个任务为gdb
     */
@RequestMapping(value = "taskGdbExport", produces = "text/html;charset=UTF-8")
public String taskGdbExport(Integer taskId, HttpServletResponse response) throws IOException {
    ogr.RegisterAll();
    gdal.AllRegister();
    // 支持中文路径和中文字段名
    gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
    gdal.SetConfigOption("SHAPE_ENCODING", "");

    Task task = taskService.getTaskById(taskId);
    if (task == null) return ResultMessage.failed("任务不存在").toString();

    String exportDir = CommonConstant.TEMP_FILE_PATHNAME + "/" + System.currentTimeMillis();
    File exportDirFile = new File(exportDir);
    exportDirFile.mkdirs();

    String gdbPath = exportTaskToGdb(task, exportDir);
    if (gdbPath == null) return ResultMessage.failed("导出失败").toString();

    String zipFilePath = StoreMediaFileUtil.zip(exportDir, Collections.singletonList(gdbPath), null);
    File zipFile = new File(zipFilePath);

    response.setContentType("application/x-zip-compressed");
    response.addHeader("Content-Disposition",
            "attachment;fileName=" + new String(task.getTaskName().getBytes(StandardCharsets.UTF_8), "iso-8859-1") + ".zip");
    String result = OtherUtil.uploadFileByResponse(zipFile, response);

    FileUtils.deleteDirectory(exportDirFile);
    zipFile.delete();

    return CommonConstant.FAILED.equals(result) ? ResultMessage.failed(null).toString() : ResultMessage.success(null).toString();
}
    /**
     * 批量下载数据接口
     */
    @RequestMapping(value = "batchGdbExport", produces = "text/html;charset=UTF-8")
    public String batchGdbExport(@RequestParam List<Integer> taskIds, HttpServletResponse response) throws IOException {
        if (taskIds == null || taskIds.isEmpty()) return ResultMessage.failed("任务ID列表为空").toString();

        ogr.RegisterAll();
        gdal.AllRegister();
        // 支持中文路径和中文字段名
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES");
        gdal.SetConfigOption("SHAPE_ENCODING", "");

        String exportDir = CommonConstant.TEMP_FILE_PATHNAME + "/" + System.currentTimeMillis();
        File exportDirFile = new File(exportDir);
        exportDirFile.mkdirs();

        List<String> gdbPaths = new ArrayList<>();
        for (Integer taskId : taskIds) {
            Task task = taskService.getTaskById(taskId);
            if (task == null) continue;
            String gdbPath = exportTaskToGdb(task, exportDir);
            if (gdbPath != null) gdbPaths.add(gdbPath);
        }

        if (gdbPaths.isEmpty()) return ResultMessage.failed("没有有效任务可导出").toString();

        String zipFilePath = StoreMediaFileUtil.zip(exportDir, gdbPaths, null);
        File zipFile = new File(zipFilePath);

        // ✅ 使用日期+“批量数据下载”作为压缩包名称
        String dateStr = new SimpleDateFormat("yyyyMMdd").format(new Date());
        String zipFileName = dateStr + "批量数据下载.zip";

        response.setContentType("application/x-zip-compressed");
        response.addHeader("Content-Disposition",
                "attachment;fileName=" + new String(zipFileName.getBytes(StandardCharsets.UTF_8), "iso-8859-1"));
        String result = OtherUtil.uploadFileByResponse(zipFile, response);

        FileUtils.deleteDirectory(exportDirFile);
        zipFile.delete();

        return CommonConstant.FAILED.equals(result) ? ResultMessage.failed(null).toString() : ResultMessage.success(null).toString();
    }


    /**
     * 为一个任务创建 GDB 并写入所有表
     *
     * @param task 任务对象
     * @param exportBaseDir 临时导出根目录
     * @return 返回生成的 GDB 绝对路径
     */
    public String exportTaskToGdb(Task task, String exportBaseDir) throws IOException {
        if (task == null) return null;

        Config config = JSON.toJavaObject(JSON.parseObject(task.getConfig()), Config.class);
        Map<String, Table> tableMap = config.getTables();
        if (tableMap == null || tableMap.isEmpty()) {
            System.err.println("⚠️ 任务没有表：" + task.getTaskName());
            return null;
        }

        // 临时 GDB 路径
        String gdbName = task.getTaskName() + ".gdb";
        File gdbDir = new File(exportBaseDir, gdbName);
        if (gdbDir.exists()) {
            try {
                FileUtils.deleteDirectory(gdbDir);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        // 创建 FileGDB 数据源
        Driver driver = ogr.GetDriverByName("FileGDB");
        if (driver == null) throw new RuntimeException("未找到 FileGDB 驱动");
        DataSource dataSource = driver.CreateDataSource(gdbDir.getAbsolutePath());
        if (dataSource == null) {
            System.err.println("⚠️ 创建 GDB 失败：" + gdbDir.getAbsolutePath());
            return null;
        }

        // 遍历表
        for (Map.Entry<String, Table> entry : tableMap.entrySet()) {
            String tableName = entry.getKey();
            Table table = entry.getValue();
            String layerName = table.getName(); // 使用中文名作为图层名

            String tableNameInDb = PostgreSqlUtil.buildTableNameString(task.getDatabaseName(), tableName, false, false);
            String selectSql = MessageFormat.format(SqlStringConstant.SELECT_ALLDATA_SQL, tableNameInDb);
            List<Map<String, Object>> tableDataList = baseService.selectData(selectSql);

            if (tableDataList == null || tableDataList.isEmpty()) {
                continue;
            }

            boolean hasGeometry = tableDataList.stream().anyMatch(row -> {
                Object geom = row.get("shape");
                return geom != null && !geom.toString().trim().isEmpty();
            });

            if (hasGeometry) {
                addGeometryLayerToGdb(dataSource, table, layerName, tableDataList);
            } else {
                addTableToGdb(dataSource, table, layerName, tableDataList);
            }
        }

        dataSource.delete(); // 保存并关闭 GDB
        return gdbDir.getAbsolutePath();
    }

    /**
     * 添加带几何的图层到 GDB（支持 Polygon 和 MultiPolygon）
     */
    private void addGeometryLayerToGdb(DataSource dataSource, Table table, String layerName, List<Map<String, Object>> dataList) {
        SpatialReference srs = new SpatialReference();
        srs.ImportFromEPSG(4490); // CGCS2000

        // ✅ 直接从 JSON 中解析几何类型
        int geomType = ogr.wkbPolygon; // 默认 Polygon
        for (Map<String, Object> row : dataList) {
            Object geomObj = row.get("shape");
            if (geomObj == null || geomObj.toString().trim().isEmpty()) continue;

            try {
                JSONObject json = JSONObject.parseObject(geomObj.toString());
                String type = json.getString("type");

                if ("MultiPolygon".equalsIgnoreCase(type)) {
                    geomType = ogr.wkbMultiPolygon;
                } else if ("Polygon".equalsIgnoreCase(type)) {
                    geomType = ogr.wkbPolygon;
                } else if ("Point".equalsIgnoreCase(type)) {
                    geomType = ogr.wkbPoint;
                }
                break;
            } catch (Exception ignore) {}
        }

        // ✅ 创建图层
        Layer layer = dataSource.CreateLayer(layerName, srs, geomType);
        if (layer == null) {
            System.err.println("❌ 创建几何图层失败：" + layerName);
            return;
        }

        // ✅ 字段顺序
        List<String> fieldNameOrder = genFieldNameOrderStringArr(table, "");
        if (fieldNameOrder == null || fieldNameOrder.isEmpty()) return;

        // ✅ 字段创建（英文名 + 中文别名）
        for (String fieldName : fieldNameOrder) {
            Field field = table.getFields().get(fieldName);
            String alias = (field != null && field.getName() != null) ? field.getName() : fieldName;

            FieldDefn fieldDefn = new FieldDefn(fieldName, ogr.OFTString);
            try {
                fieldDefn.SetAlternativeName(alias);
            } catch (Exception ignore) {}
            layer.CreateField(fieldDefn);
        }

        // ✅ 写入要素（严格匹配几何类型）
        for (Map<String, Object> row : dataList) {
            Feature feature = new Feature(layer.GetLayerDefn());

            // 属性写入
            for (String fieldName : fieldNameOrder) {
                Object val = row.get(fieldName);
                feature.SetField(fieldName, val == null ? "" : val.toString());
            }

            // 几何写入
            Object geomObj = row.get("shape");
            if (geomObj != null && !geomObj.toString().trim().isEmpty()) {
                try {
                    Geometry geometry = Geometry.CreateFromJson(geomObj.toString());
                    // ✅ 只有类型一致时写入，否则跳过（不报错）
                    if (geometry != null && geometry.GetGeometryType() == geomType) {
                        feature.SetGeometry(geometry);
                    }
                } catch (Exception e) {
                    System.err.println("⚠️ 几何解析失败：" + e.getMessage());
                }
            }

            layer.CreateFeature(feature);
            feature.delete();
        }

        layer.SyncToDisk();
    }


    /**
     * 添加普通表到 GDB（无几何）
     */
    private void addTableToGdb(DataSource dataSource, Table table, String layerName, List<Map<String, Object>> dataList) {
        // ✅ 创建普通表图层
        Layer layer = dataSource.CreateLayer(layerName, null, ogr.wkbNone);
        if (layer == null) {
            System.err.println("❌ 创建普通表失败：" + layerName);
            return;
        }

        // ✅ 获取字段顺序
        String primaryKey = TableOperationUtil.getPrimaryKey(table);
        List<String> fieldNameOrder = genFieldNameOrderStringArr(table, "");
        if (fieldNameOrder == null || fieldNameOrder.isEmpty()) {
            return;
        }

        // ✅ 创建字段（英文名 + 中文别名）
        for (String fieldName : fieldNameOrder) {
            if (fieldName == null || fieldName.trim().isEmpty()) continue;

            Field field = table.getFields().get(fieldName);
            String aliasName = (field != null && field.getName() != null) ? field.getName() : fieldName;

            FieldDefn fieldDefn = new FieldDefn(fieldName, ogr.OFTString);
            try {
                fieldDefn.SetAlternativeName(aliasName);
            } catch (Exception e) {
                System.err.println("⚠️ 设置别名失败：" + fieldName + " → " + aliasName);
            }
            layer.CreateField(fieldDefn);
        }

        // ✅ 写入行
        for (Map<String, Object> row : dataList) {
            FeatureDefn featureDefn = layer.GetLayerDefn();
            Feature feature = new Feature(featureDefn);

            for (String fieldName : fieldNameOrder) {
                Object val = row.get(fieldName);
                feature.SetField(fieldName, val == null ? "" : val.toString());
            }

            layer.CreateFeature(feature);
            feature.delete();
        }

        layer.SyncToDisk();
    }


    // 导出 Excel 文件
//    private void exportExcelFile(Table table, List<Map<String, Object>> dataList, String exportDir, Map<Integer, String> idToRealName) throws IOException {
//        String primaryKey = TableOperationUtil.getPrimaryKey(table);
//        List<String> fieldNameOrder = genFieldNameOrderStringArr(table, "");
//
//        Workbook workbook = new XSSFWorkbook();
//        Sheet sheet = workbook.createSheet("Sheet1");
//        Row firstRow = sheet.createRow(0);
//        firstRow.createCell(0).setCellValue(primaryKey);
//        for (int i = 0; i < fieldNameOrder.size(); i++) {
//            firstRow.createCell(i + 1).setCellValue(fieldNameOrder.get(i));
//        }
//        int rowNum = 1;
//        for (Map<String, Object> rowData : dataList) {
//            Row row = sheet.createRow(rowNum++);
//            row.createCell(0).setCellValue(rowData.get(primaryKey).toString());
//            for (int i = 0; i < fieldNameOrder.size(); i++) {
//                String fieldName = fieldNameOrder.get(i);
//                row.createCell(i + 1).setCellValue(rowData.getOrDefault(fieldName, "").toString());
//            }
//        }
//        try (FileOutputStream fos = new FileOutputStream(new File(exportDir, table.getName() + ".xlsx"))) {
//            workbook.write(fos);
//        }
//    }
    //导出Excel文件，根据字段类型对应导出
    private void exportExcelFile(Table table, List<Map<String, Object>> dataList, String exportDir, Map<Integer, String> idToRealName) throws IOException {
        String primaryKey = TableOperationUtil.getPrimaryKey(table);
        List<String> fieldNameOrder = genFieldNameOrderStringArr(table, "");

        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");

        // 写表头
        Row firstRow = sheet.createRow(0);
        firstRow.createCell(0).setCellValue(primaryKey);
        for (int i = 0; i < fieldNameOrder.size(); i++) {
            firstRow.createCell(i + 1).setCellValue(fieldNameOrder.get(i));
        }

        // 写数据
        int rowNum = 1;
        for (Map<String, Object> rowData : dataList) {
            Row row = sheet.createRow(rowNum++);

            // 主键列
            Object primaryKeyVal = rowData.get(primaryKey);
            Cell pkCell = row.createCell(0);
            if (primaryKeyVal == null) {
                pkCell.setBlank();
            } else if (primaryKeyVal instanceof Number) {
                pkCell.setCellValue(((Number) primaryKeyVal).doubleValue());
            } else if (primaryKeyVal instanceof Boolean) {
                pkCell.setCellValue((Boolean) primaryKeyVal);
            }  else {
                pkCell.setCellValue(primaryKeyVal.toString());
            }

            // 其他字段列
            for (int i = 0; i < fieldNameOrder.size(); i++) {
                String fieldName = fieldNameOrder.get(i);
                Object value = rowData.getOrDefault(fieldName, null);
                Cell cell = row.createCell(i + 1);

                if (value == null) {
                    cell.setBlank();
                } else if (value instanceof Number) {
                    cell.setCellValue(((Number) value).doubleValue());
                } else if (value instanceof Boolean) {
                    cell.setCellValue((Boolean) value);
                } else {
                    cell.setCellValue(value.toString());
                }
            }
        }

        // 写入文件
        try (FileOutputStream fos = new FileOutputStream(new File(exportDir, table.getName() + ".xlsx"))) {
            workbook.write(fos);
        }
    }


    /**
     * 因为数据库中没有将点线面数据分开，所以需要创建点线面三个shp，
     * 这里为了方便，三个 shp 的名字分别是 Point 、LineString、Polygon
     */
//    private void createShpByGeometryType(Table table, List<Map<String, Object>> tableDataList,
//                                         String geometryType, String shpNamePrefix, boolean isHighVersion,
//                                         Map<Integer, String> idToRealName) throws IOException{
//        // 创建shp文件并写入数据
//        String shpFilePath = CommonConstant.TEMP_FILE_PATHNAME + "/" + shpNamePrefix + "/" + geometryType + ".shp";
//        File shpFile = new File(shpFilePath);
//        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
//        Map<String, Serializable> params = new HashMap<>();
//        params.put("url", shpFile.toURI().toURL());
//        params.put("create spatial index", Boolean.TRUE);
//        ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
//        try{
//            SimpleFeatureType type = DataUtilities.createType("Location", genTypeSpec(table, geometryType,tableDataList));
//            GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
//            SimpleFeatureBuilder simpleFeatureBuilder = new SimpleFeatureBuilder(type);
//            String shapeFieldName = CheckTableDataUtil.getGeometryFieldName(table);
//            String primaryKey = TableOperationUtil.getPrimaryKey(table);
//            // 将数据转换为简单要素
//            List<SimpleFeature> features = new ArrayList<>();
//            List<String> fieldNameOrderList = genFieldNameOrderStringArr(table, TableOperationUtil.getCameraFieldName(table));
//            for(Map<String, Object> tableData : tableDataList){
//                JSONObject jsonObject = (JSONObject) JSONObject.parse(tableData.get(shapeFieldName).toString());
//                // 针对不同类型进行不同处理
//                if(geometryType.equals(CommonConstant.POLYGON) && jsonObject.getString("type").equals(CommonConstant.POLYGON)){
//                    Polygon polygon = geometryFactory.createPolygon(genCoordinateArrByPolygon((List<List<List<Object>>>)jsonObject.get("coordinates")));
//                    features.add(createFeature(simpleFeatureBuilder, polygon, tableData, primaryKey, fieldNameOrderList, idToRealName));
//                }
//                if(geometryType.equals(CommonConstant.LINESTRING) && jsonObject.getString("type").equals(CommonConstant.LINESTRING)){
//                    LineString lineString = geometryFactory.createLineString(genCoordinateArrByLineString((List<List<Object>>) jsonObject.get("coordinates")));
//                    features.add(createFeature(simpleFeatureBuilder, lineString, tableData, primaryKey, fieldNameOrderList, idToRealName));
//                }
//                if(geometryType.equals(CommonConstant.POINT) && jsonObject.getString("type").equals(CommonConstant.POINT)){
//                    Point point = geometryFactory.createPoint(genCoordinateArrByPoint((List<Object>) jsonObject.get("coordinates")));
//                    features.add(createFeature(simpleFeatureBuilder, point, tableData, primaryKey, fieldNameOrderList, idToRealName));
//                }
//            }
//            // 针对不同的版本使用不同的编码
//            if(isHighVersion){
//                newDataStore.setCharset(StandardCharsets.UTF_8);
//            }
//            else{
//                newDataStore.setCharset(Charset.forName("GBK"));
//            }
//            newDataStore.createSchema(type);
//            Transaction transaction = new DefaultTransaction("create");
//            String typeName = newDataStore.getTypeNames()[0];
//            SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
//            if(featureSource instanceof SimpleFeatureStore){
//                SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
//                SimpleFeatureCollection collection = new ListFeatureCollection(type, features);
//                featureStore.setTransaction(transaction);
//                try{
//                    featureStore.addFeatures(collection);
//                    transaction.commit();
//                } catch(Exception problem){
//                    problem.printStackTrace();
//                    transaction.rollback();
//                } finally{
//                    transaction.close();
//                }
//            }
//        } catch(Exception e){
//            e.printStackTrace();
//        } finally{
//            newDataStore.dispose();
//        }
//    }
    private void createShpByGeometryType(Table table, List<Map<String, Object>> tableDataList,
                                         String geometryType, String shpNamePrefix, boolean isHighVersion,
                                         Map<Integer, String> idToRealName) throws IOException {
        // 创建shp文件并写入数据
        String shpFilePath = CommonConstant.TEMP_FILE_PATHNAME + "/" + shpNamePrefix + "/" + geometryType + ".shp";
        File shpFile = new File(shpFilePath);
        ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory();
        Map<String, Serializable> params = new HashMap<>();
        params.put("url", shpFile.toURI().toURL());
        params.put("create spatial index", Boolean.TRUE);
        ShapefileDataStore newDataStore = (ShapefileDataStore) dataStoreFactory.createNewDataStore(params);
        try {
            SimpleFeatureType type = DataUtilities.createType("Location", genTypeSpec(table, geometryType, tableDataList));
            GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
            SimpleFeatureBuilder simpleFeatureBuilder = new SimpleFeatureBuilder(type);
            String shapeFieldName = CheckTableDataUtil.getGeometryFieldName(table);
            String primaryKey = TableOperationUtil.getPrimaryKey(table);
            // 将数据转换为简单要素
            List<SimpleFeature> features = new ArrayList<>();
            List<String> fieldNameOrderList = genFieldNameOrderStringArr(table, TableOperationUtil.getCameraFieldName(table));
            for (Map<String, Object> tableData : tableDataList) {
                JSONObject jsonObject = (JSONObject) JSONObject.parse(tableData.get(shapeFieldName).toString());
                String geomType = jsonObject.getString("type");
                if ("Polygon".equalsIgnoreCase(geometryType) && "Polygon".equalsIgnoreCase(geomType)) {
//                    // 传入的坐标是 List<List<Object>> 类型，直接调用
//                    Polygon polygon = geometryFactory.createPolygon(genCoordinateArrByPolygon((List<List<List<Object>>>)jsonObject.get("coordinates")));
//                    features.add(createFeature(simpleFeatureBuilder, polygon, tableData, primaryKey, fieldNameOrderList, idToRealName));
                    // 坐标是 List<List<List<Object>>>：外环 + 内环
                    List<List<List<Object>>> coords = (List<List<List<Object>>>) jsonObject.get("coordinates");

                    // 外环
                    Coordinate[] shell = genCoordinateArrByLinearRing(coords.get(0));
                    LinearRing shellRing = geometryFactory.createLinearRing(shell);

                    // 内环（可能没有）
                    LinearRing[] holes = new LinearRing[coords.size() - 1];
                    for (int i = 1; i < coords.size(); i++) {
                        Coordinate[] holeCoords = genCoordinateArrByLinearRing(coords.get(i));
                        holes[i - 1] = geometryFactory.createLinearRing(holeCoords);
                    }

                    Polygon polygon = geometryFactory.createPolygon(shellRing, holes);
                    features.add(createFeature(simpleFeatureBuilder, polygon, tableData, primaryKey, fieldNameOrderList, idToRealName));
                }
                else if ("MultiPolygon".equalsIgnoreCase(geometryType) && "MultiPolygon".equalsIgnoreCase(geomType)) {
                    // 坐标是 List<List<List<List<Object>>>>
                    List<List<List<List<Object>>>> coords = (List<List<List<List<Object>>>>) jsonObject.get("coordinates");
                    Polygon[] polygons = new Polygon[coords.size()];
                    for (int i = 0; i < coords.size(); i++) {
                        List<List<List<Object>>> polygonCoords = coords.get(i);
                        // 外环
                        Coordinate[] shell = genCoordinateArrByLinearRing(polygonCoords.get(0));
                        LinearRing shellRing = geometryFactory.createLinearRing(shell);

                        // 内环
                        LinearRing[] holes = new LinearRing[polygonCoords.size() - 1];
                        for (int j = 1; j < polygonCoords.size(); j++) {
                            Coordinate[] holeCoords = genCoordinateArrByLinearRing(polygonCoords.get(j));
                            holes[j - 1] = geometryFactory.createLinearRing(holeCoords);
                        }

                        polygons[i] = geometryFactory.createPolygon(shellRing, holes);
                    }

                    MultiPolygon multiPolygon = geometryFactory.createMultiPolygon(polygons);
                    features.add(createFeature(simpleFeatureBuilder, multiPolygon, tableData, primaryKey, fieldNameOrderList, idToRealName));
                }

                else if ("LineString".equalsIgnoreCase(geometryType) && "LineString".equalsIgnoreCase(geomType)) {
                    LineString lineString = geometryFactory.createLineString(genCoordinateArrByLineString((List<List<Object>>) jsonObject.get("coordinates")));
                    features.add(createFeature(simpleFeatureBuilder, lineString, tableData, primaryKey, fieldNameOrderList, idToRealName));
                }
                else if ("Point".equalsIgnoreCase(geometryType) && "Point".equalsIgnoreCase(geomType)) {
                    Point point = geometryFactory.createPoint(genCoordinateArrByPoint((List<Object>) jsonObject.get("coordinates")));
                    features.add(createFeature(simpleFeatureBuilder, point, tableData, primaryKey, fieldNameOrderList, idToRealName));
                }
            }

            // 编码设置
            if (isHighVersion) {
                newDataStore.setCharset(StandardCharsets.UTF_8);
            } else {
                newDataStore.setCharset(Charset.forName("GBK"));
            }
            newDataStore.createSchema(type);
            Transaction transaction = new DefaultTransaction("create");
            String typeName = newDataStore.getTypeNames()[0];
            SimpleFeatureSource featureSource = newDataStore.getFeatureSource(typeName);
            if (featureSource instanceof SimpleFeatureStore) {
                SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
                SimpleFeatureCollection collection = new ListFeatureCollection(type, features);
                featureStore.setTransaction(transaction);
                try {
                    featureStore.addFeatures(collection);
                    transaction.commit();
                } catch (Exception problem) {
                    problem.printStackTrace();
                    transaction.rollback();
                } finally {
                    transaction.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            newDataStore.dispose();
        }
    }

//    private SimpleFeature createFeature(SimpleFeatureBuilder builder,
//                                        Object geometry,
//                                        Map<String, Object> tableData,
//                                        String primaryKey,
//                                        List<String> fieldNameOrderList,
//                                        Map<Integer, String> idToRealName) {
//        // 添加几何要素
//        builder.add(geometry);
//        // 添加属性字段
//        builder.add(tableData.get(primaryKey));
//        fieldNameOrderList.forEach(fieldName -> {
//            if(CommonConstant.FIX_FIELD_STATUS.equals(fieldName)){
//                Object statusValue = tableData.get(fieldName);
//                int status = 0; // 默认值
//                if (statusValue != null && !"null".equalsIgnoreCase(String.valueOf(statusValue))) {
//                    try {
//                        status = Integer.parseInt(String.valueOf(statusValue));
//                    } catch (NumberFormatException e) {
//                        logger.warn("Invalid status value: {}", statusValue);
//                    }
//                }
//                builder.add(OtherUtil.getStatusMeaning(status));
//            } else if (CommonConstant.FIX_FIELD_COLLECTOR.equals(fieldName) || CommonConstant.FIX_FIELD_REVIEWER.equals(fieldName)) {
//                int userId = (int) tableData.getOrDefault(fieldName, -1);
//                builder.add(idToRealName.computeIfAbsent(userId, userService::findRealNameById));
//            } else {
//                builder.add(tableData.getOrDefault(fieldName, ""));
//            }
//        });
//        return builder.buildFeature(null);
//    }
private SimpleFeature createFeature(SimpleFeatureBuilder builder,
                                    Object geometry,
                                    Map<String, Object> tableData,
                                    String primaryKey,
                                    List<String> fieldNameOrderList,
                                    Map<Integer, String> idToRealName) {
    // 添加几何要素
    builder.add(geometry);

    // 添加主键（默认是 Integer）
    Object pkVal = tableData.get(primaryKey);
    builder.add((pkVal instanceof Number) ? pkVal : null); // 避免写入 "" 导致类型不匹配

    // 添加字段属性
    for (String fieldName : fieldNameOrderList) {
        Object value = tableData.get(fieldName);
        // 特殊字段：状态值翻译
        if (CommonConstant.FIX_FIELD_STATUS.equals(fieldName)) {
            int status = 0;
            if (value != null && !"null".equalsIgnoreCase(String.valueOf(value))) {
                try {
                    status = Integer.parseInt(String.valueOf(value));
                } catch (NumberFormatException e) {
                    logger.warn("Invalid status value: {}", value);
                }
            }
            builder.add(OtherUtil.getStatusMeaning(status));
        }

        // 特殊字段：采集人/审核人ID转真实姓名
        else if (CommonConstant.FIX_FIELD_COLLECTOR.equals(fieldName) || CommonConstant.FIX_FIELD_REVIEWER.equals(fieldName)) {
            int userId = -1;

            if (value instanceof Integer) {
                userId = (int) value;
            } else if (value != null) {
                try {
                    userId = Integer.parseInt(String.valueOf(value));
                } catch (NumberFormatException e) {
                    logger.warn("Invalid user ID value: {}", value);
                }
            }
            builder.add(idToRealName.computeIfAbsent(userId, userService::findRealNameById));
        }

        // 普通字段：保持类型一致
        else {
            if (value == null || "null".equalsIgnoreCase(String.valueOf(value))) {
                builder.add(null); // null 是 GeoTools 允许的缺失值
            } else if (value instanceof Integer || value instanceof Long ||
                    value instanceof Double || value instanceof Float ||
                    value instanceof Boolean || value instanceof Date) {
                builder.add(value); // 保留原始类型
            } else {
                builder.add(value.toString()); // 其他转为 String（如 BigDecimal、Map 等）
            }
        }
    }

    return builder.buildFeature(null);
}


    /**
     * 根据 Table 的字段的 index 大小，生成字段名的 List<String>，
     * 注意该 List<String> 中排除了主键和空间字段(如果存在)
     */
    private List<String> genFieldNameOrderStringArr(Table table, String cameraFieldName){
        Map<String, Field> fields = table.getFields();
        List<String> result = new ArrayList<>();
        fields.forEach((fieldKey, field) -> {
            if(!field.isIdentity() && !field.isGeometry() && !CommonConstant.FIX_FIELD_SET.contains(fieldKey)
                    && StringUtils.isBlank(field.getAssociate()) && StringUtils.isBlank(field.getCollection())
                    && (!fieldKey.equals(cameraFieldName))){
                result.add(fieldKey);
            }
        });
        result.sort(Comparator.comparingInt(o -> fields.get(o).getIndex()));
        // 需要把 "审核状态" 和 "未通过原因" 添加进去
        result.add(CommonConstant.FIX_FIELD_STATUS);
        result.add(CommonConstant.FIX_FIELD_REASON);
        result.add(CommonConstant.FIX_FIELD_CREATE_TIME);
        result.add(CommonConstant.FIX_FIELD_UPDATE_TIME);
        result.add(CommonConstant.FIX_FIELD_COLLECTOR);
        result.add(CommonConstant.FIX_FIELD_REVIEWER);
        return result;
    }

    /**
     * 根据根表创建 DataUtilities.createType() 的 typeSpec 参数
     * 原始代码：把除了主键以外的所有字段都强行定义为了：String，2025.7.9修改，根据字段值类型动态定义字段类型
     */
//    private String genTypeSpec(Table table, String geometryType){
//        List<String> fieldNameOrderList = genFieldNameOrderStringArr(table, TableOperationUtil.getCameraFieldName(table));
//        String primaryKey = TableOperationUtil.getPrimaryKey(table);
//        StringBuilder result = new StringBuilder("the_geom:").append(geometryType)
//                .append(":srid=4490,").append(primaryKey).append(":Integer,");
//        // 注意 ShapeFile 规定字段名不能超过10characters
//        fieldNameOrderList.forEach(fieldName -> result.append(fieldName.length() > 10 ? fieldName.substring(0, 10) : fieldName).append(":String,"));
//        return result.substring(0, result.length() - 1);
//    }
    /**
     * 根据根表数据动态创建 Shapefile 的字段类型定义（typeSpec）
     */
//    private String genTypeSpec(Table table, String geometryType, List<Map<String, Object>> tableDataList) {
//        List<String> fieldNameOrderList = genFieldNameOrderStringArr(table, TableOperationUtil.getCameraFieldName(table));
//        String primaryKey = TableOperationUtil.getPrimaryKey(table);
//
//        // 提取第一条非空数据用于字段类型推断（可以换成更鲁棒的推断方法）
//        Map<String, Object> firstData = null;
//        for (Map<String, Object> row : tableDataList) {
//            if (row != null && !row.isEmpty()) {
//                firstData = row;
//                break;
//            }
//        }
//
//        if (firstData == null) {
//            throw new IllegalArgumentException("数据为空，无法推断字段类型");
//        }
//
//        StringBuilder result = new StringBuilder("the_geom:")
//                .append(geometryType)
//                .append(":srid=4490,")
//                .append(primaryKey)
//                .append(":Integer,");
//
//        for (String fieldName : fieldNameOrderList) {
//            String truncatedField = fieldName.length() > 10 ? fieldName.substring(0, 10) : fieldName;
//            Object value = firstData.get(fieldName);
//
//            String type;
//            if (value instanceof Integer || value instanceof Long) {
//                type = "Integer";
//            } else if (value instanceof Double || value instanceof Float || value instanceof BigDecimal) {
//                type = "Double";
//            } else if (value instanceof Boolean) {
//                type = "Boolean";
//            } else if (value instanceof Date) {
//                type = "Date";
//            } else {
//                type = "String";
//            }
//
//            result.append(truncatedField).append(":").append(type).append(",");
//        }
//
//        return result.substring(0, result.length() - 1);
//    }
    private String genTypeSpec(Table table, String geometryType, List<Map<String, Object>> tableDataList) {
        List<String> fieldNameOrderList = genFieldNameOrderStringArr(table, TableOperationUtil.getCameraFieldName(table));
        String primaryKey = TableOperationUtil.getPrimaryKey(table);

        // 提取第一条非空数据用于字段类型推断
        Map<String, Object> firstData = null;
        for (Map<String, Object> row : tableDataList) {
            if (row != null && !row.isEmpty()) {
                firstData = row;
                break;
            }
        }

        if (firstData == null) {
            throw new IllegalArgumentException("数据为空，无法推断字段类型");
        }

        StringBuilder result = new StringBuilder("the_geom:")
                .append(geometryType)
                .append(":srid=4490,")
                .append(primaryKey)
                .append(":Integer,");

        for (String fieldName : fieldNameOrderList) {
            String truncatedField = fieldName.length() > 10 ? fieldName.substring(0, 10) : fieldName;

            // 👇 强制定义为 String 的字段（避免类型不匹配）
            if (CommonConstant.FIX_FIELD_COLLECTOR.equals(fieldName)
                    || CommonConstant.FIX_FIELD_REVIEWER.equals(fieldName)
                    || CommonConstant.FIX_FIELD_STATUS.equals(fieldName)) {
                result.append(truncatedField).append(":String,");
                continue;
            }

            Object value = firstData.get(fieldName);
            String type;

            if (value instanceof Integer || value instanceof Long) {
                type = "Integer";
            } else if (value instanceof Double || value instanceof Float || value instanceof BigDecimal) {
                type = "Double";
            } else if (value instanceof Boolean) {
                type = "Boolean";
            } else if (value instanceof Date) {
                type = "Date";
            } else {
                type = "String";
            }

            result.append(truncatedField).append(":").append(type).append(",");
        }

        // 去掉最后一个逗号
        return result.substring(0, result.length() - 1);
    }


    /**
     * 根据 shape 的 coordinate 属性构建 Coordinate，针对于 type 为 Point
     */
    private Coordinate genCoordinateArrByPoint(List<Object> coord){
        double x = Double.parseDouble(String.valueOf(coord.get(0)));
        double y = Double.parseDouble(String.valueOf(coord.get(1)));
        return new Coordinate(x, y);
    }


    /**
     * 根据 shape 的 coordinate 属性构建Coordinate[]，针对于 type 为 LineString
     */
    private Coordinate[] genCoordinateArrByLineString(List<List<Object>> coord){
        List<Coordinate> coordinates = new ArrayList<>();
        Coordinate[] coordinateArr = new Coordinate[]{};
        if(CollectionUtils.isNotEmpty(coord)){
            for(List<Object> list : coord){
                coordinates.add(genCoordinateArrByPoint(list));
            }
        }
        return coordinates.toArray(coordinateArr);
    }

    /**
     * 根据 shape 的 coordinate 属性构建 Coordinate[]，针对于 type 为 Polygon
     */
    private Coordinate[] genCoordinateArrByPolygon(List<List<List<Object>>> coord){
        List<Coordinate> coordinates = new ArrayList<>();
        Coordinate[] coordinateArr = new Coordinate[]{};
        if(CollectionUtils.isNotEmpty(coord)){
            List<List<Object>> tempList = coord.get(0);
            for(List<Object> list : tempList){
                coordinates.add(genCoordinateArrByPoint(list));
            }
        }
        return coordinates.toArray(coordinateArr);
    }
    /**
     * 处理一个 ring（外环或内环）：List<List<Object>> → Coordinate[]
     */
    private Coordinate[] genCoordinateArrByLinearRing(List<List<Object>> ringCoords) {
        List<Coordinate> coordinates = new ArrayList<>();
        for (List<Object> point : ringCoords) {
            coordinates.add(genCoordinateArrByPoint(point));
        }
        return coordinates.toArray(new Coordinate[0]);
    }



    /**
     * 将多媒体表导出为 CSV （该接口为导出工具专用）
     */
    @RequestMapping("mediaTable")
    public String exportMediaTable(int taskId, String tableName, HttpServletResponse response) {
        Optional<File> optional = exportService.exportMediaTable(taskId, tableName);
        return optional.isPresent() ? transferFile(response, optional.get()) : new ResultMessage<>(false, "无法导出多媒体表").toString() ;
    }

    /**
     * 将采集人员和巡查人员信息导出为 CSV （该接口为导出工具专用）
     */
    @RequestMapping("users")
    public String exportUsers(int taskId, HttpServletResponse response) {
        Optional<File> optional = exportService.exportUsers(taskId);
        return optional.isPresent() ? transferFile(response, optional.get()) : new ResultMessage<>(false, "无法导出用户表").toString();
    }

    private String transferFile(HttpServletResponse response, File file) {
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM.toString());
        response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
        try (OutputStream out = response.getOutputStream()) {
            Files.copy(file.toPath(), out);
            return new ResultMessage<>(true, "").toString();
        } catch (IOException e) {
            logger.error(e.getMessage());
            return new ResultMessage<>(false, "").toString();
        } finally {
            if (!file.delete()) {
                logger.warn("无法删除文件 " + file.getAbsolutePath());
            }
        }
    }
}
