package com.rj.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rj.common.AudioManagementConstants;
import com.rj.entity.*;
import com.rj.mapper.DeviceManagementMapper;
import com.rj.tenant.TenantContextHolder;
import com.rj.service.IAudioManagementService;
import com.rj.service.IFileUploadService;
import com.rj.service.MinIOService;
import com.rj.service.IYhyAudioUploadLogService;
import com.rj.service.IYhyHeartbeatLogService;
import com.rj.service.IYhyDatatypeLogService;
import com.rj.common.TimeZoneUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.math.BigDecimal;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * 音频文件访问控制器
 * 音频文件大小和时长
 *
 * 音频文件不超过2GB；时长在12小时以内。
 *
 * @author 李中华 ,spllzh
 * @since 2025-08-07
 */
@RestController
@RequestMapping("/api/audio")
@Tag(name = "音频文件", description = "音频文件上传和访问相关接口")
@Slf4j
public class AudioFileController {

    @Autowired
    private IFileUploadService fileUploadService;
    
    @Autowired
    private IAudioManagementService audioManagementService;

    @Value("${app.audio.upload.path:uploads/audio}")
    private String uploadPath;
    
    @Value("${app.audio.upload.yihangyi.path:/home/lizh/java_env/AIDriverEEBackend/audio/yihangyi}")
    private String yihangyiUploadPath;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Autowired
    private MinIOService minIOService;
    
    @Autowired
    private IYhyAudioUploadLogService yhyAudioUploadLogService;
    
    @Autowired
    private IYhyHeartbeatLogService heartbeatLogService;
    
    @Autowired
    private IYhyDatatypeLogService yhyDatatypeLogService;
    
    @Autowired
    private com.rj.common.ServiceManager serviceManager;
    
    @Autowired
    private DeviceManagementMapper deviceManagementMapper;
    
    @Autowired
    private com.rj.service.IAudioManagementSegmentsService audioManagementSegmentsService;

    public  String  deviceKey = "deviceManagementKey";
    /**
     * v1 推送回调接口
     * 支持两种请求方式：
     * 1. JSON格式：包含文件路径等信息，需要从指定路径读取文件
     * 2. multipart/form-data格式：包含实际文件和JSON数据
     * 
     * 参考C#实现：接收任意JSON对象，打印headers和body
     *
     * @param requestData JSON数据字符串（当Content-Type为multipart/form-data时，通过data参数传递）
     * @param file 上传的文件（可选，当Content-Type为multipart/form-data时）
     * @param request HttpServletRequest
     * @return 响应结果
     */
    @PostMapping(value = "/v1/callback", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.ALL_VALUE})
    @Operation(summary = "推送回调接口v1", description = "接收推送回调请求，支持JSON和multipart/form-data格式，自动处理文件上传")
    public ResponseEntity<Map<String, Object>> yhyV1Push(
            @Parameter(description = "JSON数据字符串（multipart/form-data格式时使用）")
            @RequestParam(value = "data", required = false) String requestData,
            @Parameter(description = "上传的文件（multipart/form-data格式时使用）")
            @RequestParam(value = "file", required = false) MultipartFile file,
            HttpServletRequest request) {
        long startTime = System.currentTimeMillis();
        log.info("接收推送回调请求，yuehangyi，20251129,requestData:{}", requestData);
        
        try {
            // 1. 提取请求头
            Map<String, String> headers = extractRequestHeaders(request);
            String headersJson = objectMapper.writeValueAsString(headers);
            log.info("headers: {}", headersJson);

            // 2. 从multipart请求中提取文件（如果存在）
            MultipartFile extractedFile = extractFileFromMultipartRequest(request, file);
            file = extractedFile; // 统一使用提取后的文件

            // 3. 解析请求体
            Map<String, Object> requestBody = parseRequestBody(request, requestData);
            
            // 打印请求体
            String bodyJson = objectMapper.writeValueAsString(requestBody);
            log.info("body: {}", bodyJson);
            
            // 4. 保存原始数据到 yhy_datatype_log 表
            try {
                saveDatatypeLog(headers, requestBody);
            } catch (Exception e) {
                log.error("保存数据到yhy_datatype_log表失败", e);
                // 即使保存失败，也不影响后续业务处理，只记录日志
            }
            
            // 5. 如果请求体为空，只记录日志，不处理业务逻辑
            if (requestBody == null || requestBody.isEmpty()) {
                log.info("请求体为空，仅记录日志，不处理业务逻辑");
                log.info("yhyV1Push 执行耗时 requestBody 为空 : {} ms", System.currentTimeMillis() - startTime);
                return ResponseEntity.ok(createEmptyRequestBodyResponse());
            }
            
            // 6. 提取数据类型和设备号
            String dataType = extractDataType(requestBody);
            String deviceNo = (String) requestBody.get("deviceNo");
            log.info("检测到数据类型: {}", dataType);
            boolean retFlag  = false;
            // 6.1. 根据设备编号查询租户ID（绕过多租户拦截器）
            if (deviceNo != null && !deviceNo.trim().isEmpty()) {
                try {
                    // 使用 Mapper 方法绕过多租户拦截器，不添加 tenant_id 查询条件
                    DeviceManagement deviceManagement = deviceManagementMapper.selectByDeviceCodeIgnoreTenant(deviceNo);
                    
                    if (deviceManagement != null && deviceManagement.getTenantId() != null) {
                        String tenantId = deviceManagement.getTenantId();
                        requestBody.put(deviceKey, deviceManagement);
                        log.info("根据设备编号 {} 查询到租户ID: {}", deviceNo, tenantId);
                    } else {
                        log.warn("未找到设备编号 {} 对应的设备信息或租户ID为空", deviceNo);
                        retFlag = true;
                    }
                } catch (Exception e) {
                    log.error("查询设备租户ID失败，设备编号: {}", deviceNo, e);
                    retFlag = true;
                    // 查询失败不影响后续流程，只记录日志
                }
            } else {
                log.warn("设备编号为空，无法查询租户ID");
                retFlag = true;

            }
            if (retFlag){
                Map<String, Object> result = new HashMap<>();
                result.put("success", false);
                result.put("message",  "设备编号为空或被绑定租户，无法查询租户ID");
                log.info("yhyV1Push 执行耗时 ，设备变化为空 : {} ms", System.currentTimeMillis() - startTime);
                return ResponseEntity.ok(result);
            }

            // 7. 处理业务逻辑 ,保存文件， 上传
            ProcessResult processResult = processByDataType(dataType, requestBody, file, request);
            
            // 8. 构建并返回响应
            Map<String, Object> result = buildSuccessResponse(deviceNo, dataType, 
                    processResult.getLocalFilePath(), processResult.getResult());
            
            log.info("推送回调处理完成，设备号: {}, 数据类型: {}, 本地路径: {}", 
                    deviceNo, dataType, processResult.getLocalFilePath());
            log.info("响应数据: {}", result);
            log.info("yhyV1Push 执行耗时 处理完业务Audio : {} ms", System.currentTimeMillis() - startTime);
            if ("Audio".equals(dataType)){
                log.info("yhyV1Push 执行耗时 处理完业务Audio : {} ms", System.currentTimeMillis() - startTime);
            }
            return ResponseEntity.ok(result);
            
        } catch (Exception e) {
            log.error("处理推送回调异常", e);
            log.info("yhyV1Push 执行耗时 Exception: {} ms", System.currentTimeMillis() - startTime);
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "处理异常: " + e.getMessage());
            return ResponseEntity.internalServerError().body(result);
        }
    }
    
    /**
     * 提取数据类型（兼容新旧数据结构）
     * 
     * @param requestBody 请求体
     * @return 数据类型
     */
    private String extractDataType(Map<String, Object> requestBody) {
        String dataType = (String) requestBody.get("dataType");
        if (dataType == null || dataType.trim().isEmpty()) {
            // 兼容旧的数据结构，尝试从pushDataType获取
            dataType = (String) requestBody.get("pushDataType");
        }
        return dataType;
    }
    
    /**
     * 创建空请求体响应
     * 
     * @return 响应Map
     */
    private Map<String, Object> createEmptyRequestBodyResponse() {
        Map<String, Object> result = new HashMap<>();
        result.put("success", true);
        result.put("message", "请求接收成功（请求体为空）");
        return result;
    }
    
    /**
     * 处理结果包装类
     */
    private static class ProcessResult {
        private final Map<String, Object> result;
        private final String localFilePath;
        
        public ProcessResult(Map<String, Object> result, String localFilePath) {
            this.result = result;
            this.localFilePath = localFilePath;
        }
        
        public Map<String, Object> getResult() {
            return result;
        }
        
        public String getLocalFilePath() {
            return localFilePath;
        }
    }
    
    /**
     * 根据数据类型处理业务逻辑
     * 
     * @param dataType 数据类型
     * @param requestBody 请求体
     * @param file 文件
     * @param request HTTP请求
     * @return 处理结果
     */
    private ProcessResult processByDataType(String dataType, Map<String, Object> requestBody, 
                                           MultipartFile file, HttpServletRequest request) {
        Map<String, Object> processResult = null;
        String localFilePath = null;
        
        if (dataType == null || dataType.trim().isEmpty()) {
            log.warn("未识别到数据类型，跳过业务处理");
            processResult = new HashMap<>();
            processResult.put("success", true);
            processResult.put("message", "未识别到数据类型，仅记录日志");
            return new ProcessResult(processResult, null);
        }
        
        switch (dataType) {
            case "Audio":
                processResult = processAudioDataType(requestBody, file, request);
                break;
            case "HeartbeatLog":
                processResult = heartbeatLogService.processHeartbeatReport(requestBody);
                break;
            case "Gps":
                log.info("收到GPS日志数据，设备号: {}", requestBody.get("deviceNo"));
                processResult = handleGpsDataType(requestBody);
                break;
            case "AudioText":
                log.info("收到语音转写数据，设备号: {}", requestBody.get("deviceNo"));
                // 收到语音转写数据 ， 不再处理： 保存数据库 ，用python 处理
//                processResult = handleAudioTextDataType(requestBody);
                log.info("---------------------AudioText不再保存数据库-----------------------------");
                break;
            case "LoginLog":
                log.info("收到登录日志数据，设备号: {}", requestBody.get("deviceNo"));
                processResult = handleLoginLogDataType(requestBody);
                break;
            case "ControlLog":
                log.info("收到操控日志数据，设备号: {}", requestBody.get("deviceNo"));
                processResult = handleControlLogDataType(requestBody);
                break;
            case "UploadLog":
                log.info("收到上传日志数据，设备号: {}", requestBody.get("deviceNo"));
                processResult = handleUploadLogDataType(requestBody, file);
                break;
            case "DebugLog":
                log.info("收到运行日志数据，设备号: {}", requestBody.get("deviceNo"));
                processResult = handleDebugLogDataType(requestBody);
                break;
            case "MergeAudio":
                log.info("收到合并录音数据，设备号: {}", requestBody.get("deviceNo"));
                processResult = handleMergeAudioDataType(requestBody);
                break;
            default:
                log.warn("未知的数据类型: {}, 设备号: {}", dataType, requestBody.get("deviceNo"));
                processResult = new HashMap<>();
                processResult.put("success", true);
                processResult.put("message", "未知的数据类型: " + dataType);
                break;
        }
        
        if (processResult != null && processResult.get("localFilePath") != null) {
            localFilePath = (String) processResult.get("localFilePath");
        }
        
        return new ProcessResult(processResult, localFilePath);
    }
    
    /**
     * 处理Audio数据类型
     * 
     * @param requestBody 请求体
     * @param file 文件
     * @param request HTTP请求
     * @return 处理结果
     */
    private Map<String, Object> processAudioDataType(Map<String, Object> requestBody, 
                                                     MultipartFile file, 
                                                     HttpServletRequest request) {
        log.info("检测到数据类型Audio----------开始处理--------------------");
        
        // 再次尝试获取文件（如果之前没有获取到），没有保存
        MultipartFile audioFile = extractFileFromMultipartRequest(request, file);
        
        // 关联上传的文件到audio_management表 ，计算录音总时长 ，标记为 服务开始 的记录不能超过 1 天
        associateAudioManagement(requestBody);
        
        // 处理Audio数据 验证文件、保存文件到本地、保存信息到数据库, 计算录音  总时长 ，标记为 服务结束
        Map<String, Object> processResult = handleAudioDataType(requestBody, audioFile);
        
        log.info("检测到数据类型Audio-----------处理结束-------------------");
        return processResult;
    }
    

    /**
     * 上传音频文件
     */
    @PostMapping("/upload")
    @Operation(summary = "上传音频文件", description = "上传音频文件并关联到录音记录")
    public ResponseEntity<Map<String, Object>> uploadAudioFile(
            @Parameter(description = "音频文件", required = true)
            @RequestParam("file") MultipartFile file,
            @Parameter(description = "录音ID", required = true)
            @RequestParam("audioId") String audioId,
            @RequestParam("audioDuration") BigDecimal audioDuration ) {
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 先按 yhyV1Push 相同逻辑保存到本地目录（优先savePath，否则yihangyiUploadPath）
            String localFileName = determineFileName(file, new HashMap<>(), null);
            String localFilePath = saveAudioFileToLocal(file, localFileName, new HashMap<>(), null);

            Map<String, Object> uploadResult = fileUploadService.uploadAudioFileAndUpdateRecord(file, audioId);
            
            if ((Boolean) uploadResult.get("success")) {
                // 手动上传成功后，把本地落盘信息写回 audio_management 表
                AudioManagement audioManagement = audioManagementService.getById(audioId);
                if (audioManagement != null) {
                    audioManagement.setUpdateTime(TimeZoneUtils.now());
                    audioManagementService.updateById(audioManagement);
                    // 同步回写 audio_management_segments（子表）
                    saveOrUpdateManualUploadSegment(audioManagement, file,audioDuration, localFileName, localFilePath, uploadResult);
                } else {
                    log.warn("手动上传后未找到录音记录，无法回写本地路径：audioId={}", audioId);
                }

                result.put("success", true);
                result.put("message", "音频文件上传成功");
                result.put("localFilePath", localFilePath);
                result.put("data", uploadResult);
                return ResponseEntity.ok(result);
            } else {
                result.put("success", false);
                result.put("message", uploadResult.get("message"));
                return ResponseEntity.badRequest().body(result);
            }
            
        } catch (IOException e) {
            log.error("音频文件上传失败：audioId={}, error={}", audioId, e.getMessage(), e);
            result.put("success", false);
            result.put("message", "文件上传失败：" + e.getMessage());
            return ResponseEntity.internalServerError().body(result);
        }
    }
    
    /**
     * 手动上传时，回写 audio_management_segments 子表。
     * 若存在相同 parentId + audioFilePath 的记录则更新，否则新建一条分段记录。
     */
    private void saveOrUpdateManualUploadSegment(AudioManagement audioManagement,
                                                 MultipartFile file,
                                                 BigDecimal audioDuration,
                                                 String localFileName,
                                                 String localFilePath,
                                                 Map<String, Object> uploadResult) {
        try {
            LambdaQueryWrapper<AudioManagementSegments> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AudioManagementSegments::getParentId, audioManagement.getId())
                    .eq(AudioManagementSegments::getAudioFilePath, localFilePath)
                    .last("LIMIT 1");
            AudioManagementSegments segment = audioManagementSegmentsService.getOne(queryWrapper, false);

            LocalDateTime now = TimeZoneUtils.now();
            boolean isNew = false;
            if (segment == null) {
                isNew = true;
                segment = new AudioManagementSegments();
                segment.setId(UUID.randomUUID().toString());
                segment.setParentId(audioManagement.getId());
                segment.setTenantId(audioManagement.getTenantId());
                segment.setRecordingName(audioManagement.getRecordingName());
                segment.setSalesId(audioManagement.getSalesId());
                segment.setSalesPhone(audioManagement.getSalesPhone());
                segment.setSalesName(audioManagement.getSalesName());
                segment.setDealershipId(audioManagement.getDealershipId());
                segment.setDealershipName(audioManagement.getDealershipName());
                segment.setScenario(audioManagement.getScenario());
                segment.setChunkIndex("1");
                segment.setCreateTime(now);
                segment.setUploadStatus("已上传");
                segment.setSyncStatus("未同步");
                segment.setIsMerged(false);
            }

            segment.setAudioFilePath(localFilePath);
            segment.setAudioFileOriginalName(file.getOriginalFilename());
            segment.setAudioFileExtension(getFileExtension(localFileName));
            segment.setAudioFileSize(file.getSize());
            segment.setUploadTime(now);
            segment.setRecordingTime(audioManagement.getRecordingTime() != null ? audioManagement.getRecordingTime() : now);
            segment.setDuration(audioDuration);

            if (isNew) {
                audioManagementSegmentsService.save(segment);
            } else {
                audioManagementSegmentsService.updateById(segment);
            }
        } catch (Exception e) {
            log.error("手动上传后回写audio_management_segments失败，audioId={}", audioManagement.getId(), e);
        }
    }

    /**
     * 获取音频文件
     */
    @GetMapping("/{fileName}")
    @Operation(summary = "获取音频文件", description = "根据文件名获取音频文件")
    public ResponseEntity<Resource> getAudioFile(
            @Parameter(description = "文件名", required = true)
            @PathVariable String fileName) {
        
        try {
            Path filePath = Paths.get(uploadPath, fileName);
            File file = filePath.toFile();
            
            if (!file.exists() || !file.isFile()) {
                return ResponseEntity.notFound().build();
            }

            // 检查文件是否为音频文件
            if (!isAudioFile(fileName)) {
                return ResponseEntity.badRequest().build();
            }

            Resource resource = new FileSystemResource(file);
            
            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType(getContentType(fileName)));
            headers.setContentLength(file.length());
            headers.set("Accept-Ranges", "bytes");
            
            return ResponseEntity.ok()
                    .headers(headers)
                    .body(resource);
                    
        } catch (Exception e) {
            log.error("获取音频文件失败：fileName={}, error={}", fileName, e.getMessage(), e);
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 删除音频文件
     */
    @DeleteMapping("/{audioId}")
    @Operation(summary = "删除音频文件", description = "根据录音ID删除音频文件")
    public ResponseEntity<Map<String, Object>> deleteAudioFile(
            @Parameter(description = "录音ID", required = true)
            @PathVariable String audioId) {
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            boolean deleted = fileUploadService.deleteAudioFile(audioId);
            
            if (deleted) {
                result.put("success", true);
                result.put("message", "音频文件删除成功");
                return ResponseEntity.ok(result);
            } else {
                result.put("success", false);
                result.put("message", "音频文件不存在或删除失败");
                return ResponseEntity.notFound().build();
            }
            
        } catch (Exception e) {
            log.error("删除音频文件失败：audioId={}, error={}", audioId, e.getMessage(), e);
            result.put("success", false);
            result.put("message", "删除失败：" + e.getMessage());
            return ResponseEntity.internalServerError().body(result);
        }
    }

    /**
     * 检查音频文件是否存在
     */
    @GetMapping("/exists/{audioId}")
    @Operation(summary = "检查音频文件是否存在", description = "根据录音ID检查音频文件是否存在")
    public ResponseEntity<Map<String, Object>> checkAudioFileExists(
            @Parameter(description = "录音ID", required = true)
            @PathVariable String audioId) {
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            boolean exists = fileUploadService.audioFileExists(audioId);
            String fileUrl = null;
            
            if (exists) {
                fileUrl = fileUploadService.getAudioFileUrl(audioId);
            }
            
            result.put("success", true);
            result.put("exists", exists);
            result.put("fileUrl", fileUrl);
            
            return ResponseEntity.ok(result);
            
        } catch (Exception e) {
            log.error("检查音频文件失败：audioId={}, error={}", audioId, e.getMessage(), e);
            result.put("success", false);
            result.put("message", "检查失败：" + e.getMessage());
            return ResponseEntity.internalServerError().body(result);
        }
    }

    @GetMapping("/download/{filename:.+}") // 使用 {.+} 匹配包含点的完整文件名
    public ResponseEntity<Resource> serveAudio(@PathVariable String filename) throws IOException {
        // 1. 构建文件路径，防止路径遍历攻击
        // Path audioLocation = Paths.get("path/to/your/audio/files");
        // Path filePath = audioLocation.resolve(filename).normalize();
        // if (!filePath.startsWith(audioLocation)) {
        //     return ResponseEntity.badRequest().build(); // 安全检查
        // }

        // 2. 检查文件是否存在
        // if (!Files.exists(filePath) || !Files.isRegularFile(filePath)) {
        //     return ResponseEntity.notFound().build();
        // }

        // 3. 创建 Resource 对象
        Resource resource = new UrlResource(filename);

        // 4. 设置响应头：关键！让浏览器下载而不是播放
        String downloadFilename = "downloaded_audio.mp3"; // 你希望用户保存的文件名
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + downloadFilename + "\"")
                .contentType(MediaType.APPLICATION_OCTET_STREAM) // 通用二进制流，确保下载
                // 或者使用音频 MIME 类型，但配合 attachment 头也能下载
                // .contentType(MediaType.parseMediaType("audio/mpeg"))
                .body(resource);
    }
    /**
     * 获取音频文件信息
     */
    @GetMapping("/info/{audioId}")
    @Operation(summary = "获取音频文件信息", description = "根据录音ID获取音频文件详细信息")
    public ResponseEntity<Map<String, Object>> getAudioFileInfo(
            @Parameter(description = "录音ID", required = true)
            @PathVariable String audioId) {
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            boolean exists = fileUploadService.audioFileExists(audioId);
            
            if (!exists) {
                result.put("success", false);
                result.put("message", "音频文件不存在");
                return ResponseEntity.notFound().build();
            }

            String fileUrl = fileUploadService.getAudioFileUrl(audioId);
            Path uploadDir = Paths.get(uploadPath);
            File dir = uploadDir.toFile();
            
            File[] files = dir.listFiles((d, name) -> name.startsWith(audioId + "."));
            if (files != null && files.length > 0) {
                File file = files[0];
                
                Map<String, Object> fileInfo = new HashMap<>();
                fileInfo.put("fileName", file.getName());
                fileInfo.put("fileSize", file.length());
                fileInfo.put("fileUrl", fileUrl);
                fileInfo.put("lastModified", file.lastModified());
                fileInfo.put("contentType", getContentType(file.getName()));
                
                result.put("success", true);
                result.put("data", fileInfo);
                
                return ResponseEntity.ok(result);
            }
            
            result.put("success", false);
            result.put("message", "音频文件信息获取失败");
            return ResponseEntity.internalServerError().body(result);
            
        } catch (Exception e) {
            log.error("获取音频文件信息失败：audioId={}, error={}", audioId, e.getMessage(), e);
            result.put("success", false);
            result.put("message", "获取文件信息失败：" + e.getMessage());
            return ResponseEntity.internalServerError().body(result);
        }
    }

    /**
     * 检查是否为音频文件
     */
    private boolean isAudioFile(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return false;
        }
        
        String extension = getFileExtension(fileName).toLowerCase();
        String[] audioExtensions = {"mp3", "wav", "m4a", "aac", "ogg", "flac", "wma"};
        
        for (String ext : audioExtensions) {
            if (ext.equals(extension)) {
                return true;
            }
        }
        
        return false;
    }

    /**
     * 处理音频文件上传
     * 包括：验证文件、保存文件到本地、保存信息到数据库
     * 
     * @param requestBody 请求体数据
     * @param processedData 处理后的数据
     * @param file 上传的文件
     * @param deviceNo 设备号
     * @param filePath 文件路径
     * @return 处理结果，包含success、message、localFilePath等
     */
    private Map<String, Object> handleAudioUpload(Map<String, Object> requestBody,
                                                   Map<String, Object> processedData,
                                                   MultipartFile file,
                                                   String deviceNo,
                                                   String filePath) {
        try {
            // 1. 验证文件
            Map<String, Object> validationResult = validateUploadFile(file);
            if (validationResult != null) {
                return validationResult; // 验证失败，返回错误结果
            }
            
            logFileUploadInfo(file);
            
            // 2. 确定文件名
            String fileName = determineFileName(file, processedData, filePath);
            
            // 3. 保存文件到本地
            String localFilePath = saveFileWithErrorHandling(file, fileName, processedData, deviceNo);
            if (localFilePath == null) {
                return createErrorResult("音频文件保存到本地失败");
            }
            
            // 4. 保存信息到数据库（失败不影响文件保存）
            saveUploadLogWithErrorHandling(requestBody, processedData, localFilePath, file);
            
            // 5. 返回成功结果
            return createSuccessResult(localFilePath, fileName);
            
        } catch (Exception e) {
            log.error("处理音频文件上传异常", e);
            return createErrorResult("处理音频文件上传异常: " + e.getMessage());
        }
    }
    
    /**
     * 验证上传的文件
     * 
     * @param file 上传的文件
     * @return 如果验证失败返回错误结果Map，验证成功返回null
     */
    private Map<String, Object> validateUploadFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            log.warn("文件参数为空或文件为空，file: {}, isEmpty: {}", 
                    file == null ? "null" : "not null", 
                    file != null ? file.isEmpty() : "N/A");
            return createErrorResult("音频文件上传失败：未检测到文件");
        }
        return null;
    }
    
    /**
     * 记录文件上传信息
     * 
     * @param file 上传的文件
     */
    private void logFileUploadInfo(MultipartFile file) {
        log.info("开始处理音频文件上传，文件名: {}, 大小: {} bytes, ContentType: {}", 
                file.getOriginalFilename(), file.getSize(), file.getContentType());
    }
    
    /**
     * 确定文件名
     * 优先级：1. processedData中的fileName 2. filePath中的文件名 3. 原始文件名
     * 
     * @param file 上传的文件
     * @param processedData 处理后的数据
     * @param filePath 文件路径
     * @return 确定的文件名
     */
    private String determineFileName(MultipartFile file, Map<String, Object> processedData, String filePath) {
        // 优先使用processedData中的fileName
        if (processedData != null && processedData.get("fileName") != null) {
            return (String) processedData.get("fileName");
        }
        
        // 其次使用filePath中的文件名
        if (filePath != null && !filePath.isEmpty()) {
            int lastSeparatorIndex = filePath.lastIndexOf("/");
            if (lastSeparatorIndex >= 0 && lastSeparatorIndex < filePath.length() - 1) {
                return filePath.substring(lastSeparatorIndex + 1);
            }
        }
        
        // 最后使用原始文件名
        return file.getOriginalFilename();
    }
    
    /**
     * 保存文件并处理错误
     * 
     * @param file 上传的文件
     * @param fileName 文件名
     * @param processedData 处理后的数据
     * @param deviceNo 设备号
     * @return 保存后的文件路径，如果保存失败返回null
     */
    private String saveFileWithErrorHandling(MultipartFile file, String fileName, 
                                             Map<String, Object> processedData, String deviceNo) {
        try {
            String localFilePath = saveAudioFileToLocal(file, fileName, processedData, deviceNo);
            log.info("音频文件保存到本地成功，路径: {}", localFilePath);
            return localFilePath;
        } catch (Exception e) {
            log.error("音频文件保存到本地失败", e);
            return null;
        }
    }
    
    /**
     * 保存上传日志并处理错误（失败不影响文件保存）
     * 
     * @param requestBody 请求体数据
     * @param processedData 处理后的数据
     * @param localFilePath 本地文件路径
     * @param file 上传的文件
     */
    private void saveUploadLogWithErrorHandling(Map<String, Object> requestBody, 
                                                Map<String, Object> processedData,
                                                String localFilePath, 
                                                MultipartFile file) {
        try {
            saveAudioUploadLogToDatabase(requestBody, processedData, localFilePath, file);
            log.info("音频上传日志保存到数据库成功");
        } catch (Exception e) {
            log.error("音频上传日志保存到数据库失败", e);
            // 即使数据库保存失败，也不影响文件保存，只记录日志
        }
    }
    
    /**
     * 创建成功结果
     * 
     * @param localFilePath 本地文件路径
     * @param fileName 文件名
     * @return 成功结果Map
     */
    private Map<String, Object> createSuccessResult(String localFilePath, String fileName) {
        Map<String, Object> result = new HashMap<>();
        result.put("success", true);
        result.put("message", "音频文件上传处理成功");
        result.put("localFilePath", localFilePath);
        result.put("fileName", fileName);
        return result;
    }
    
    /**
     * 创建错误结果
     * 
     * @param message 错误消息
     * @return 错误结果Map
     */
    private Map<String, Object> createErrorResult(String message) {
        Map<String, Object> result = new HashMap<>();
        result.put("success", false);
        result.put("message", message);
        return result;
    }
    
    /**
     * 保存音频文件到本地
     * 
     * @param file 上传的文件
     * @param fileName 文件名
     * @param processedData 处理后的数据
     * @param deviceNo 设备号
     * @return 保存后的文件绝对路径
     * @throws IOException 文件保存异常
     */
    private String saveAudioFileToLocal(MultipartFile file, String fileName, 
                                         Map<String, Object> processedData, String deviceNo) throws IOException {
        validateFile(file);
        
        // 确定保存路径
        String baseSavePath = determineSavePath(processedData);
        
        // 准备上传目录
        Path uploadDir = prepareUploadDirectory(baseSavePath);
        
        // 保存文件到磁盘
        Path filePath = saveFileToDisk(file, fileName, uploadDir);
        
        // 验证保存的文件
        validateSavedFile(filePath, file);
        
        String absolutePath = filePath.toAbsolutePath().toString();
        log.info("最终返回的文件路径: {}", absolutePath);
        return absolutePath;
    }
    
    /**
     * 验证文件是否有效
     * 
     * @param file 上传的文件
     * @throws IllegalArgumentException 如果文件为空
     */
    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
    }
    
    /**
     * 确定保存路径
     * 优先级：1. processedData中的savePath 2. yihangyi路径 3. 默认uploadPath
     * 
     * @param processedData 处理后的数据
     * @return 保存路径
     */
    private String determineSavePath(Map<String, Object> processedData) {
        if (processedData != null && processedData.get("savePath") != null) {
            String savePathFromData = (String) processedData.get("savePath");
            if (savePathFromData != null && !savePathFromData.trim().isEmpty()) {
                return savePathFromData;
            }
        }
            // 当接收到文件上传请求时，使用yihangyi目录
        log.info("检测到文件上传请求，使用yihangyi保存路径: {}", yihangyiUploadPath);
        return yihangyiUploadPath;
    }
    
    /**
     * 准备上传目录（创建目录并验证权限）
     * 
     * @param baseSavePath 基础保存路径
     * @return 上传目录的Path对象
     * @throws IOException 如果目录创建失败或不可写
     */
    private Path prepareUploadDirectory(String baseSavePath) throws IOException {
        Path uploadDir = Paths.get(baseSavePath);
        log.info("准备保存文件到目录: {} (绝对路径: {})", baseSavePath, uploadDir.toAbsolutePath());
        
        // 创建目录（如果不存在）
        if (!Files.exists(uploadDir)) {
            try {
            Files.createDirectories(uploadDir);
                log.info("创建上传目录成功: {}", uploadDir.toAbsolutePath());
            } catch (Exception e) {
                log.error("创建上传目录失败: {}", uploadDir.toAbsolutePath(), e);
                throw new IOException("无法创建上传目录: " + uploadDir.toAbsolutePath(), e);
            }
        } else {
            log.info("上传目录已存在: {}", uploadDir.toAbsolutePath());
        }
        
        // 验证目录是否可写
        if (!Files.isWritable(uploadDir)) {
            log.error("上传目录不可写: {}", uploadDir.toAbsolutePath());
            throw new IOException("上传目录不可写: " + uploadDir.toAbsolutePath());
        }
        
        return uploadDir;
    }
    
    /**
     * 保存文件到磁盘
     * 
     * @param file 上传的文件
     * @param fileName 文件名
     * @param uploadDir 上传目录
     * @return 保存后的文件Path对象
     * @throws IOException 如果文件保存失败
     */
    private Path saveFileToDisk(MultipartFile file, String fileName, Path uploadDir) throws IOException {
        Path filePath = uploadDir.resolve(fileName);
        
        // 如果文件已存在，先删除（可选，根据业务需求决定）
        if (Files.exists(filePath)) {
            log.warn("文件已存在，将被覆盖: {}", filePath.toAbsolutePath());
            Files.delete(filePath);
        }
        
        // 保存文件
        long bytesCopied = Files.copy(file.getInputStream(), filePath);
        log.info("文件复制完成，复制字节数: {}, 文件路径: {}", bytesCopied, filePath.toAbsolutePath());
        
        return filePath;
    }
    
    /**
     * 验证保存的文件（存在性、大小、可读性）
     * 
     * @param filePath 文件路径
     * @param originalFile 原始上传的文件
     * @throws IOException 如果验证失败
     */
    private void validateSavedFile(Path filePath, MultipartFile originalFile) throws IOException {
        // 验证文件是否真的存在
        if (!Files.exists(filePath)) {
            throw new IOException("文件保存失败：文件不存在于路径 " + filePath.toAbsolutePath());
        }
        
        // 验证文件大小
        long fileSize = Files.size(filePath);
        if (fileSize != originalFile.getSize()) {
            log.warn("文件大小不匹配，期望: {} bytes, 实际: {} bytes", originalFile.getSize(), fileSize);
        }
        
        // 验证文件是否可读
        if (!Files.isReadable(filePath)) {
            log.warn("文件不可读: {}", filePath.toAbsolutePath());
        }
        
        // 记录文件的完整信息
        logFileAttributes(filePath, fileSize);
        
        // 延迟验证（防止文件系统延迟）
        performDelayedValidation(filePath);
    }
    
    /**
     * 记录文件属性信息
     * 
     * @param filePath 文件路径
     * @param fileSize 文件大小
     */
    private void logFileAttributes(Path filePath, long fileSize) {
        try {
            java.nio.file.attribute.BasicFileAttributes attrs = Files.readAttributes(filePath, 
                    java.nio.file.attribute.BasicFileAttributes.class);
            log.info("文件保存成功并验证通过，路径: {}, 大小: {} bytes, 创建时间: {}, 修改时间: {}", 
                    filePath.toAbsolutePath(), fileSize, attrs.creationTime(), attrs.lastModifiedTime());
        } catch (Exception e) {
            log.warn("无法读取文件属性: {}", e.getMessage());
        }
    }
    
    /**
     * 执行延迟验证（等待一小段时间后再次检查文件是否存在，防止文件系统延迟）
     * 
     * @param filePath 文件路径
     * @throws IOException 如果延迟验证失败
     */
    private void performDelayedValidation(Path filePath) throws IOException {
        try {
            Thread.sleep(100); // 等待100毫秒
            if (!Files.exists(filePath)) {
                log.error("延迟验证失败：文件在保存后消失了！路径: {}", filePath.toAbsolutePath());
                throw new IOException("文件保存后验证失败：文件不存在于路径 " + filePath.toAbsolutePath());
            }
            log.info("延迟验证通过：文件仍然存在");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.warn("延迟验证被中断");
        }
    }
    
    /**
     * 保存音频上传日志到数据库
     * 
     * @param requestBody 请求体数据
     * @param processedData 处理后的数据
     * @param localFilePath 本地文件路径
     * @param file 上传的文件（可能为null）
     */
    private void saveAudioUploadLogToDatabase(Map<String, Object> requestBody, 
                                               Map<String, Object> processedData,
                                               String localFilePath,
                                               MultipartFile file) {
        try {
            YhyAudioUploadLog audioUploadLog = createAudioUploadLog();
            
            // 从requestBody中填充字段
            populateAudioUploadLogFromRequestBody(audioUploadLog, requestBody);
            
            // 从processedData中填充字段
            if (processedData != null) {
                populateAudioUploadLogFromProcessedData(audioUploadLog, processedData);
            }
            
            // 设置本地文件路径相关的字段
            setLocalFilePathFields(audioUploadLog, localFilePath);
            
            // 设置通用字段
            setAudioUploadLogCommonFields(audioUploadLog, requestBody);
            
            // 保存到数据库
            yhyAudioUploadLogService.save(audioUploadLog);
            log.info("音频上传日志保存成功，ID: {}, 设备号: {}, 文件名: {}, audioManagementId: {}", 
                    audioUploadLog.getId(), audioUploadLog.getDeviceNo(), audioUploadLog.getFileName(), 
                    audioUploadLog.getAudioManagementId());
            
            // 保存到 audio_management_segments 表
            try {
                saveAudioManagementSegment(requestBody, processedData, localFilePath, file, audioUploadLog);
            } catch (Exception e) {
                log.error("保存音频分段记录到audio_management_segments表失败", e);
                // 即使保存失败，也不影响音频上传日志的保存，只记录日志
            }
            
        } catch (Exception e) {
            log.error("保存音频上传日志到数据库失败", e);
            throw new RuntimeException("保存音频上传日志失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 创建音频上传日志对象
     * 
     * @return 新创建的YhyAudioUploadLog对象
     */
    private YhyAudioUploadLog createAudioUploadLog() {
            YhyAudioUploadLog audioUploadLog = new YhyAudioUploadLog();
            audioUploadLog.setId(UUID.randomUUID().toString());
        log.info("创建音频上传日志对象，ID: {}", audioUploadLog.getId());
        return audioUploadLog;
    }
    
    /**
     * 从requestBody中填充音频上传日志字段
     * 
     * @param audioUploadLog 音频上传日志对象
     * @param requestBody 请求体数据
     */
    private void populateAudioUploadLogFromRequestBody(YhyAudioUploadLog audioUploadLog, 
                                                       Map<String, Object> requestBody) {
        log.info("从requestBody填充音频上传日志字段,requestBody: {}", requestBody);
            audioUploadLog.setFilePath((String) requestBody.get("filePath"));
            audioUploadLog.setContentType((String) requestBody.get("contentType"));
            audioUploadLog.setDeviceNo((String) requestBody.get("deviceNo"));
            audioUploadLog.setServerUrl((String) requestBody.get("serverUrl"));
        audioUploadLog.setPushDataType("Audio"); // 固定为Audio类型
    }
    
    /**
     * 从processedData中填充音频上传日志字段
     * 
     * @param audioUploadLog 音频上传日志对象
     * @param processedData 处理后的数据
     */
    private void populateAudioUploadLogFromProcessedData(YhyAudioUploadLog audioUploadLog, 
                                                         Map<String, Object> processedData) {
        // 基本字段
                audioUploadLog.setFileName((String) processedData.get("fileName"));
                audioUploadLog.setSavePath((String) processedData.get("savePath"));
                audioUploadLog.setChunkIndex((String) processedData.get("chunkIndex"));
                audioUploadLog.setStartTime((String) processedData.get("startTime"));
                audioUploadLog.setEndTime((String) processedData.get("endTime"));
                audioUploadLog.setUsrNo((String) processedData.get("usrNo"));
                audioUploadLog.setDeviceType((String) processedData.get("deviceType"));
                
        // 处理hasBody字段（支持Boolean和String类型）
        setHasBodyField(audioUploadLog, processedData);
        
        // 处理extended字段（JSON格式）
        setExtendedField(audioUploadLog, processedData);
        
        // 用户相关字段
        audioUploadLog.setUserId((String) processedData.get("userId"));
        audioUploadLog.setUserName((String) processedData.get("userName"));
        audioUploadLog.setUserPhone((String) processedData.get("userPhone"));
        audioUploadLog.setUserDept((String) processedData.get("userDept"));
    }
    
    /**
     * 设置hasBody字段（支持Boolean和String类型转换）
     * 
     * @param audioUploadLog 音频上传日志对象
     * @param processedData 处理后的数据
     */
    private void setHasBodyField(YhyAudioUploadLog audioUploadLog, Map<String, Object> processedData) {
                Object hasBodyObj = processedData.get("hasBody");
                if (hasBodyObj != null) {
                    if (hasBodyObj instanceof Boolean) {
                        audioUploadLog.setHasBody((Boolean) hasBodyObj);
                    } else if (hasBodyObj instanceof String) {
                        audioUploadLog.setHasBody(Boolean.parseBoolean((String) hasBodyObj));
            }
        }
    }
    
    /**
     * 设置extended字段（JSON序列化）
     * 
     * @param audioUploadLog 音频上传日志对象
     * @param processedData 处理后的数据
     */
    private void setExtendedField(YhyAudioUploadLog audioUploadLog, Map<String, Object> processedData) {
                Object extendedObj = processedData.get("extended");
                if (extendedObj != null) {
                    try {
                        audioUploadLog.setExtended(objectMapper.writeValueAsString(extendedObj));
                    } catch (Exception e) {
                        log.warn("序列化extended字段失败", e);
                        audioUploadLog.setExtended(extendedObj.toString());
                    }
                }
    }
    
    /**
     * 设置本地文件路径相关的字段
     * 如果savePath为空，使用localFilePath的目录部分
     * 
     * @param audioUploadLog 音频上传日志对象
     * @param localFilePath 本地文件路径
     */
    private void setLocalFilePathFields(YhyAudioUploadLog audioUploadLog, String localFilePath) {
            if (localFilePath != null && !localFilePath.isEmpty()) {
                if (audioUploadLog.getSavePath() == null || audioUploadLog.getSavePath().isEmpty()) {
                    int lastSeparator = localFilePath.lastIndexOf(File.separator);
                    if (lastSeparator > 0) {
                        audioUploadLog.setSavePath(localFilePath.substring(0, lastSeparator));
                }
            }
        }
    }
    
    /**
     * 设置音频上传日志的通用字段
     * 
     * @param audioUploadLog 音频上传日志对象
     * @param requestBody 请求体数据
     */
    private void setAudioUploadLogCommonFields(YhyAudioUploadLog audioUploadLog, 
                                                Map<String, Object> requestBody) {
            // 设置同步阶段（初始状态）
            audioUploadLog.setSyncStage("已上传");
            
            // 设置关联的录音管理ID（如果存在）
            Object audioManagementIdObj = requestBody.get("audioManagementId");
            if (audioManagementIdObj != null) {
                audioUploadLog.setAudioManagementId(audioManagementIdObj.toString());
                log.info("设置audioManagementId到音频上传日志: {}", audioManagementIdObj);
            }
            
            // 设置创建和更新时间（使用配置的时区）
            LocalDateTime now = TimeZoneUtils.now();
            audioUploadLog.setCreateTime(now);
            audioUploadLog.setUpdateTime(now);
    }
    
    /**
     * 保存音频分段记录到 audio_management_segments 表
     * 如果已存在相同的分段记录，则跳过保存（避免重复）
     * 
     * @param requestBody 请求体数据
     * @param processedData 处理后的数据
     * @param localFilePath 本地文件路径
     * @param file 上传的文件（可能为null）
     * @param audioUploadLog 音频上传日志对象（已保存）
     */
    private void saveAudioManagementSegment(Map<String, Object> requestBody,
                                            Map<String, Object> processedData,
                                            String localFilePath,
                                            MultipartFile file,
                                            YhyAudioUploadLog audioUploadLog) {
        try {
            // 1. 检查是否已经保存过（使用requestBody中的标记）
            String segmentSavedKey = "audioManagementSegmentSaved";
            if (requestBody.containsKey(segmentSavedKey) && Boolean.TRUE.equals(requestBody.get(segmentSavedKey))) {
                log.info("音频分段记录已保存过，跳过重复保存");
                return;
            }
            
            // 2. 创建音频分段对象
            AudioManagementSegments segment = new AudioManagementSegments();
            segment.setId(UUID.randomUUID().toString());
            
            // 3. 设置父录音ID（从requestBody中获取audioManagementId）
            Object audioManagementIdObj = requestBody.get("audioManagementId");
            if (audioManagementIdObj != null) {
                segment.setParentId(audioManagementIdObj.toString());
            }
            
            // 4. 从DeviceManagement中获取设备信息
            DeviceManagement deviceManagement = (DeviceManagement) requestBody.get(deviceKey);
            if (deviceManagement != null) {
                segment.setTenantId(deviceManagement.getTenantId());
                segment.setSalesPhone(deviceManagement.getSalesPhone());
                segment.setSalesName(deviceManagement.getSalesName());
                segment.setDealershipId(deviceManagement.getDealershipId());
                segment.setDealershipName(deviceManagement.getDealershipName());
                segment.setScenario(deviceManagement.getScenario());
            }
            
            // 5. 从requestBody和processedData中提取字段
            populateSegmentFromRequestData(segment, requestBody, processedData);
            
            // 6. 设置文件相关字段
            setSegmentFileFields(segment, localFilePath, file, audioUploadLog);
            
            // 7. 解析时间字段并计算录音时长
            parseAndSetSegmentTimeFields(segment, processedData);
            
            // 8. 检查数据库中是否已存在相同的分段记录
            if (isSegmentExists(segment)) {
                log.info("音频分段记录已存在，跳过保存。父录音ID: {}, chunkIndex: {}, deviceNo: {}, filename: {}", 
                        segment.getParentId(), segment.getChunkIndex(), segment.getDeviceNo(), segment.getAudioFileOriginalName());
                // 标记为已保存，避免后续重复检查
                requestBody.put(segmentSavedKey, true);
                return;
            }
            
            // 9. 在保存之前就设置标记，防止并发保存
            requestBody.put(segmentSavedKey, true);
            
            // 10. 从AudioManagement中获取录音名称（如果存在父录音）
            if (segment.getParentId() != null) {
               // populateSegmentFromAudioManagement(segment, segment.getParentId());
            }
            
            // 11. 设置通用字段
            LocalDateTime now = TimeZoneUtils.now();
            segment.setCreateTime(now);
            segment.setUploadTime(now);
            segment.setRecordingTime(now);
            
            // 12. 设置默认状态
            if (segment.getUploadStatus() == null) {
                segment.setUploadStatus("已上传");
            }
            if (segment.getSyncStatus() == null) {
                segment.setSyncStatus("未同步");
            }
            if (segment.getIsMerged() == null) {
                segment.setIsMerged(false);
            }
            
            // 13. 保存到数据库
            audioManagementSegmentsService.save(segment);
            log.info("音频分段记录保存成功，ID: {}, 父录音ID: {}, 设备号: {}, 文件名: {}", 
                    segment.getId(), segment.getParentId(), segment.getDeviceNo(), segment.getAudioFileOriginalName());
            
            // 14. 更新AudioManagement记录（需要设置租户上下文）
            if (segment.getParentId() != null) {
                // 保存原来的租户ID，用于后续恢复
                String originalTenantId = TenantContextHolder.getTenantId();
                String tenantId = segment.getTenantId();
                
                // 如果segment中没有tenantId，尝试从DeviceManagement中获取
                if (tenantId == null || tenantId.trim().isEmpty()) {
                    // deviceManagement 已在方法前面定义（第1163行）
                    if (deviceManagement != null && deviceManagement.getTenantId() != null) {
                        tenantId = deviceManagement.getTenantId();
                    }
                }
                
                try {
                    // 设置租户ID到上下文，使后续查询和更新自动使用该租户ID
                    if (tenantId != null && !tenantId.trim().isEmpty()) {
                        TenantContextHolder.setTenantId(tenantId);
                        log.info("设置租户ID到上下文: {}", tenantId);
                    }
                    
                    AudioManagement audioManagement = new AudioManagement();
                    audioManagement.setId(segment.getParentId());
                    
                    // 根据 parentId 查询所有 audio_management_segments 记录
                    LambdaQueryWrapper<AudioManagementSegments> parentQueryWrapper = new LambdaQueryWrapper<>();
                    parentQueryWrapper.eq(AudioManagementSegments::getParentId, segment.getParentId())
                            .orderByAsc(AudioManagementSegments::getChunkIndex); // 按 chunkIndex 排序
                    List<AudioManagementSegments> allSegments = audioManagementSegmentsService.list(parentQueryWrapper);
                    
                    // 检查是否满足设置服务状态为"服务结束"的条件
                    if (checkServiceFinishConditions(allSegments)) {
                        audioManagement.setServiceStatus(AudioManagementConstants.SERVICE_STATUS_SERVICE_FINISH);
                        log.info("满足两个条件，设置服务状态为服务结束，parentId: {}", segment.getParentId());
                    } else {
                        log.debug("未满足条件，不设置服务结束状态，parentId: {}", segment.getParentId());
                    }

                    AudioManagement byId = serviceManager.getAudioManagementService().getById(segment.getParentId());
                    if (byId != null) {
                        // 累加时长
                        BigDecimal currentDuration = byId.getDuration();
                        if (currentDuration == null) {
                            currentDuration = BigDecimal.ZERO;
                        }
                        BigDecimal segmentDuration = segment.getDuration();
                        if (segmentDuration == null) {
                            segmentDuration = BigDecimal.ZERO;
                        }
                        audioManagement.setDuration(currentDuration.add(segmentDuration));
                        audioManagement.setUpdateTime(LocalDateTime.now());
                        if (deviceManagement != null) {
                            audioManagement.setScenario(deviceManagement.getScenario());
                        }
                        serviceManager.getAudioManagementService().updateById(audioManagement);
                        log.info("成功更新AudioManagement记录，ID: {}, 累计时长: {}", segment.getParentId(), audioManagement.getDuration());
                    } else {
                        log.warn("未找到AudioManagement记录，ID: {}", segment.getParentId());
                    }
                } finally {
                    // 恢复原来的租户ID
                    if (originalTenantId != null) {
                        TenantContextHolder.setTenantId(originalTenantId);
                    } else {
                        TenantContextHolder.clear();
                    }
                }
            }
            // 标记已在保存前设置（第1190行），这里不需要再次设置
            
        } catch (Exception e) {
            log.error("保存音频分段记录到audio_management_segments表失败", e);
            throw new RuntimeException("保存音频分段记录失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 检查音频分段记录是否已存在
     * 判断标准：优先使用 audio_file_original_name，备用：parent_id + chunk_index + deviceNo + start_time（如果都存在）
     * 
     * @param segment 音频分段对象
     * @return true表示已存在，false表示不存在
     */
    private boolean isSegmentExists(AudioManagementSegments segment) {
        // 保存原来的租户ID，用于后续恢复
        String originalTenantId = TenantContextHolder.getTenantId();
        String tenantId = segment.getTenantId();
        
        try {
            // 设置租户ID到上下文，使后续查询自动使用该租户ID
            if (tenantId != null && !tenantId.trim().isEmpty()) {
                TenantContextHolder.setTenantId(tenantId);
                log.debug("设置租户ID到上下文用于检查重复记录: {}", tenantId);
            }
            
            // 优先使用 audio_file_original_name 作为主要检查条件（最可靠）
            if (segment.getAudioFileOriginalName() != null && !segment.getAudioFileOriginalName().isEmpty()) {
                LambdaQueryWrapper<AudioManagementSegments> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(AudioManagementSegments::getAudioFileOriginalName, segment.getAudioFileOriginalName());

                
                long count = audioManagementSegmentsService.count(queryWrapper);
                if (count > 0) {
                    return true;
                }
            }
            
            // 如果缺少关键字段，无法判断，返回false（允许保存）
            if (segment.getParentId() == null || segment.getParentId().isEmpty()) {
                return false;
            }
            
            // 构建查询条件（备用检查：使用其他字段组合）
            LambdaQueryWrapper<AudioManagementSegments> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AudioManagementSegments::getParentId, segment.getParentId());
            
            // chunkIndex 如果存在，则必须匹配
            if (segment.getChunkIndex() != null && !segment.getChunkIndex().isEmpty()) {
                queryWrapper.eq(AudioManagementSegments::getChunkIndex, segment.getChunkIndex());
            }
            
            // deviceNo 如果存在，则必须匹配
            if (segment.getDeviceNo() != null && !segment.getDeviceNo().isEmpty()) {
                queryWrapper.eq(AudioManagementSegments::getDeviceNo, segment.getDeviceNo());
            }
            
            // startTime 如果存在，则必须匹配（精确到秒）
            if (segment.getStartTime() != null) {
                // 使用时间范围查询（前后1秒内），避免时间精度问题
                LocalDateTime startTime = segment.getStartTime();
                queryWrapper.between(AudioManagementSegments::getStartTime, 
                        startTime.minusSeconds(1), startTime.plusSeconds(1));
            }
            
            // 如果文件路径存在，也作为判断条件之一
            if (segment.getAudioFilePath() != null && !segment.getAudioFilePath().isEmpty()) {
                queryWrapper.eq(AudioManagementSegments::getAudioFilePath, segment.getAudioFilePath());
            }
            
            // 查询是否存在
            long count = audioManagementSegmentsService.count(queryWrapper);
            return count > 0;
            
        } catch (Exception e) {
            log.warn("检查音频分段记录是否存在时发生异常，将允许保存: {}", e.getMessage());
            // 如果检查失败，允许保存（避免因为检查逻辑问题导致数据丢失）
            return false;
        } finally {
            // 恢复原来的租户ID
            if (originalTenantId != null) {
                TenantContextHolder.setTenantId(originalTenantId);
            } else {
                TenantContextHolder.clear();
            }
        }
    }
    
    /**
     * 从请求数据中填充音频分段字段
     * 
     * @param segment 音频分段对象
     * @param requestBody 请求体数据
     * @param processedData 处理后的数据
     */
    private void populateSegmentFromRequestData(AudioManagementSegments segment,
                                                Map<String, Object> requestBody,
                                                Map<String, Object> processedData) {
        // 从requestBody中提取设备号
        String deviceNo = extractStringField(requestBody, "deviceNo");
        if (deviceNo != null) {
            segment.setDeviceNo(deviceNo);
        }
        
        // 从processedData中提取字段
        if (processedData != null) {
            segment.setChunkIndex(extractStringField(processedData, "chunkIndex"));
        }

        String scenario = extractStringField(requestBody, "scenario");
        if (scenario != null) {
            segment.setScenario(scenario);
        }
    }
    
    /**
     * 设置音频分段的文件相关字段
     * 
     * @param segment 音频分段对象
     * @param localFilePath 本地文件路径
     * @param file 上传的文件（可能为null）
     * @param audioUploadLog 音频上传日志对象
     */
    private void setSegmentFileFields(AudioManagementSegments segment,
                                      String localFilePath,
                                      MultipartFile file,
                                      YhyAudioUploadLog audioUploadLog) {
        // 设置文件路径
        if (localFilePath != null && !localFilePath.isEmpty()) {
            segment.setAudioFilePath(localFilePath);
        } else if (audioUploadLog.getSavePath() != null && audioUploadLog.getFileName() != null) {
            segment.setAudioFilePath(audioUploadLog.getSavePath() + File.separator + audioUploadLog.getFileName());
        }
        
        // 设置文件原始名称
        if (file != null && file.getOriginalFilename() != null) {
            segment.setAudioFileOriginalName(file.getOriginalFilename());
        } else if (audioUploadLog.getFileName() != null) {
            segment.setAudioFileOriginalName(audioUploadLog.getFileName());
        }
        
        // 设置文件扩展名
        String fileName = segment.getAudioFileOriginalName();
        if (fileName != null) {
            String extension = getFileExtension(fileName);
            if (!extension.isEmpty()) {
                segment.setAudioFileExtension(extension);
            }
        }
        
        // 设置文件大小
        if (file != null && file.getSize() > 0) {
            segment.setAudioFileSize(file.getSize());
        }
    }
    
    /**
     * 解析时间字段并计算录音时长
     * 
     * @param segment 音频分段对象
     * @param processedData 处理后的数据
     */
    private void parseAndSetSegmentTimeFields(AudioManagementSegments segment,
                                               Map<String, Object> processedData) {
        if (processedData == null) {
            return;
        }
        
        // 解析开始时间
        LocalDateTime startTime = parseDateTimeField(processedData, "startTime");
        if (startTime != null) {
            segment.setStartTime(startTime);
        }
        
        // 解析结束时间
        LocalDateTime endTime = parseDateTimeField(processedData, "endTime");
        if (endTime != null) {
            segment.setEndTime(endTime);
        }
        
        // 计算录音时长（分钟）
        if (startTime != null && endTime != null && endTime.isAfter(startTime)) {
            long seconds = java.time.Duration.between(startTime, endTime).getSeconds();
            BigDecimal durationMinutes = BigDecimal.valueOf(seconds).divide(BigDecimal.valueOf(60), 2, 
                    java.math.RoundingMode.HALF_UP);
            segment.setDuration(durationMinutes);
        }
    }
    
    /**
     * 解析时间字段
     * 
     * @param dataMap 数据Map
     * @param fieldName 字段名
     * @return LocalDateTime对象，如果解析失败则返回null
     */
    private LocalDateTime parseDateTimeField(Map<String, Object> dataMap, String fieldName) {
        if (dataMap == null || fieldName == null) {
            return null;
        }
        
        Object timeObj = dataMap.get(fieldName);
        if (timeObj == null) {
            return null;
        }
        
        // 如果已经是LocalDateTime类型，直接返回
        if (timeObj instanceof LocalDateTime) {
            return (LocalDateTime) timeObj;
        }
        
        // 如果是String类型，尝试解析
        if (timeObj instanceof String) {
            String timeStr = (String) timeObj;
            if (timeStr.trim().isEmpty()) {
                return null;
            }
            
            try {
                // 使用TimeZoneUtils或类似的方法解析时间字符串
                // 这里简化处理，使用LocalDateTimeDeserializer的逻辑
                return parseTimeString(timeStr);
            } catch (Exception e) {
                log.warn("解析时间字段失败: {} = {}", fieldName, timeStr, e);
                return null;
            }
        }
        
        return null;
    }
    
    /**
     * 解析时间字符串
     * 支持多种格式：ISO格式、标准格式、yyMMddHHmmss格式等
     * 
     * @param timeStr 时间字符串
     * @return LocalDateTime对象
     */
    private LocalDateTime parseTimeString(String timeStr) {
        if (timeStr == null || timeStr.trim().isEmpty()) {
            return null;
        }
        
        String trimmedTimeStr = timeStr.trim();
        
        try {
            // 首先检测是否为新的时间格式：yyMMddHHmmss (12位数字)
            if (trimmedTimeStr.matches("^\\d{12}$")) {
                // 解析 yyMMddHHmmss 格式
                return LocalDateTime.parse(trimmedTimeStr, 
                        java.time.format.DateTimeFormatter.ofPattern("yyMMddHHmmss"));
            }
            
            // 检测是否包含时区信息
            boolean hasTimezone = trimmedTimeStr.endsWith("Z") || 
                                 trimmedTimeStr.matches(".*[+-]\\d{2}:\\d{2}(?:\\d{2})?$");
            
            if (hasTimezone) {
                // 处理带时区的时间
                java.time.ZonedDateTime zonedDateTime;
                if (trimmedTimeStr.endsWith("Z")) {
                    zonedDateTime = java.time.ZonedDateTime.parse(trimmedTimeStr.replace("Z", "+00:00"))
                            .withZoneSameInstant(TimeZoneUtils.getZoneId());
                } else {
                    zonedDateTime = java.time.ZonedDateTime.parse(trimmedTimeStr)
                            .withZoneSameInstant(TimeZoneUtils.getZoneId());
                }
                return zonedDateTime.toLocalDateTime();
            } else {
                // 处理不带时区的时间
                String cleanTimeStr = trimmedTimeStr;
                if (cleanTimeStr.contains("T")) {
                    cleanTimeStr = cleanTimeStr.replace("T", " ");
                }
                if (cleanTimeStr.contains(".")) {
                    cleanTimeStr = cleanTimeStr.substring(0, cleanTimeStr.indexOf("."));
                }
                if (cleanTimeStr.length() > 19) {
                    cleanTimeStr = cleanTimeStr.substring(0, 19);
                }
                return LocalDateTime.parse(cleanTimeStr, 
                        java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            }
        } catch (Exception e) {
            log.warn("解析时间字符串失败: {}", timeStr, e);
            return null;
        }
    }
    

    /**
     * 提取请求头信息
     * 
     * @param request HTTP请求
     * @return 请求头Map
     */
    private Map<String, String> extractRequestHeaders(HttpServletRequest request) {
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName, request.getHeader(headerName));
        }
        return headers;
    }
    
    /**
     * 从multipart请求中提取文件
     * 
     * @param request HTTP请求
     * @param existingFile 已存在的文件（可能为null）
     * @return 提取的文件，如果未找到则返回null
     */
    private MultipartFile extractFileFromMultipartRequest(HttpServletRequest request, MultipartFile existingFile) {
        // 如果已有文件且不为空，直接返回
        if (existingFile != null && !existingFile.isEmpty()) {
            log.info("使用已有文件，文件名: {}, 大小: {} bytes", 
                    existingFile.getOriginalFilename(), existingFile.getSize());
            return existingFile;
        }
        
        // 尝试从request中获取文件
        if (request instanceof org.springframework.web.multipart.MultipartHttpServletRequest) {
            org.springframework.web.multipart.MultipartHttpServletRequest multipartRequest = 
                (org.springframework.web.multipart.MultipartHttpServletRequest) request;
            
            // 获取所有文件参数名
            java.util.Iterator<String> fileNames = multipartRequest.getFileNames();
            if (fileNames.hasNext()) {
                String paramName = fileNames.next();
                MultipartFile file = multipartRequest.getFile(paramName);
                if (file != null && !file.isEmpty()) {
                    log.info("从multipart请求中获取到文件，参数名: {}, 文件名: {}, 大小: {} bytes", 
                            paramName, file.getOriginalFilename(), file.getSize());
                    return file;
                }
            }
        }
        
        log.warn("未找到文件");
        return null;
    }
    
    /**
     * 解析multipart/form-data格式的请求体
     * 
     * @param request HTTP请求
     * @param requestData data参数（JSON字符串）
     * @return 解析后的请求体Map
     */
    private Map<String, Object> parseMultipartRequestBody(HttpServletRequest request, String requestData) {
        Map<String, Object> requestBody = new HashMap<>();
        
        // 获取所有form-data参数（包括 dataType 等单独参数）
        Map<String, String[]> parameterMap = request.getParameterMap();
        Map<String, String> formParams = new HashMap<>();
        
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String paramName = entry.getKey();
            String[] paramValues = entry.getValue();
            // 排除 file 参数（文件参数通过 MultipartFile 处理）
            if (!"file".equals(paramName) && paramValues != null && paramValues.length > 0) {
                formParams.put(paramName, paramValues[0]);
                log.debug("获取到form-data参数: {} = {}", paramName, paramValues[0]);
            }
        }
        
        // 如果存在 data 参数，解析其 JSON 内容并合并到 requestBody
        if (requestData != null && !requestData.trim().isEmpty()) {
            try {
                Map<String, Object> dataMap = objectMapper.readValue(requestData, 
                        new TypeReference<Map<String, Object>>() {});
                if (dataMap != null) {
                    requestBody.putAll(dataMap);
                    log.info("multipart/form-data中的data参数解析成功，包含 {} 个字段", dataMap.size());
                }
        } catch (Exception e) {
                log.error("解析multipart/form-data中的data参数失败", e);
            }
        }
        
        // 将其他单独的参数合并到 requestBody 中（单独参数的优先级更高，会覆盖 data 参数中的同名字段）
        for (Map.Entry<String, String> entry : formParams.entrySet()) {
            String paramName = entry.getKey();
            if (!"data".equals(paramName)) {
                requestBody.put(paramName, entry.getValue());
                log.debug("将form-data参数 {} = {} 合并到requestBody", paramName, entry.getValue());
            }
        }
        
        log.info("multipart/form-data参数解析完成，requestBody包含 {} 个字段: {}", 
                requestBody.size(), requestBody.keySet());
        return requestBody;
    }
    
    /**
     * 解析application/json格式的请求体
     * 
     * @param request HTTP请求
     * @return 解析后的请求体Map，如果解析失败则返回空Map
     */
    private Map<String, Object> parseJsonRequestBody(HttpServletRequest request) {
        try {
            java.io.BufferedReader reader = request.getReader();
            StringBuilder bodyBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                bodyBuilder.append(line);
            }
            String bodyString = bodyBuilder.toString();
            
            if (bodyString != null && !bodyString.trim().isEmpty()) {
                log.info("从请求流读取到数据，长度: {}", bodyString.length());
                Map<String, Object> requestBody = objectMapper.readValue(bodyString, 
                        new TypeReference<Map<String, Object>>() {});
                log.info("从请求流解析JSON成功");
                return requestBody;
            } else {
                log.warn("请求体为空");
                return new HashMap<>();
            }
        } catch (Exception e) {
            log.warn("从请求流读取数据失败，可能请求体为空: {}", e.getMessage());
            return new HashMap<>();
        }
    }
    
    /**
     * 解析请求体（根据Content-Type自动选择解析方式）
     * 
     * @param request HTTP请求
     * @param requestData data参数（multipart/form-data格式时使用）
     * @return 解析后的请求体Map
     */
    private Map<String, Object> parseRequestBody(HttpServletRequest request, String requestData) {
        String contentType = request.getContentType();
        log.info("Content-Type: {}", contentType);
        
        if (contentType != null && contentType.contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
            log.info("检测到multipart/form-data格式请求");
            return parseMultipartRequestBody(request, requestData);
        } else {
            log.info("检测到application/json格式请求");
            return parseJsonRequestBody(request);
        }
    }
    
    /**
     * 构建成功响应
     * 
     * @param deviceNo 设备号
     * @param dataType 数据类型
     * @param localFilePath 本地文件路径（可选）
     * @param processResult 处理结果
     * @return 响应Map
     */
    private Map<String, Object> buildSuccessResponse(String deviceNo, String dataType, 
                                                     String localFilePath, 
                                                     Map<String, Object> processResult) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> responseData = new HashMap<>();
        
        responseData.put("deviceNo", deviceNo);
        responseData.put("dataType", dataType);
        if (localFilePath != null) {
            responseData.put("localFilePath", localFilePath);
        }
        
        if (processResult != null) {
            Boolean success = (Boolean) processResult.get("success");
            if (success != null && success) {
                result.put("success", true);
                result.put("message", processResult.get("message") != null ? 
                           processResult.get("message") : "回调处理成功");
            } else {
                result.put("success", false);
                result.put("message", processResult.get("message") != null ? 
                           processResult.get("message") : "回调处理失败");
            }
        } else {
            result.put("success", true);
            result.put("message", "回调处理成功");
        }
        
        result.put("data", responseData);
        return result;
    }
    
    /**
     * 关联Audio数据到audio_management表
     * 根据deviceNo查找或创建对应的audio_management记录，并将ID设置到requestBody中
     * 处理多条服务状态为:   服务中   的记录 , 这是不正常现象
     * @param requestBody 请求体，用于获取deviceNo，并在方法中设置audioManagementId
     */
    private void associateAudioManagement(Map<String, Object> requestBody) {
        // 保存原来的租户ID，用于后续恢复
        String originalTenantId = TenantContextHolder.getTenantId();
        
        try {
            String deviceNo = (String) requestBody.get("deviceNo");
            if (deviceNo == null || deviceNo.trim().isEmpty()) {
                log.warn("deviceNo为空，无法关联audio_management表");
                return;
            }
            
            // 1. 根据device_no去device_management表查找device_code相同的记录
            DeviceManagement deviceManagement = (DeviceManagement)requestBody.get(deviceKey);
            
            if (deviceManagement == null) {
                log.warn("deviceManagement为空，无法关联audio_management表");
                return;
            }
            
            // 1.1. 设置租户ID到上下文，使后续查询自动使用该租户ID
            String tenantId = deviceManagement.getTenantId();
            if (tenantId != null && !tenantId.trim().isEmpty()) {
                TenantContextHolder.setTenantId(tenantId);
                log.info("设置租户ID到上下文: {}", tenantId);
            } else {
                log.warn("deviceManagement中的tenantId为空，无法设置租户上下文");
                return;
            }
            // 3. 根据sales_name和sales_phone去audio_management表查找sync_status='服务中'的记录
            LambdaQueryWrapper<AudioManagement> audioQuery = new LambdaQueryWrapper<>();
            audioQuery.eq(AudioManagement::getSalesPhone, deviceManagement.getSalesPhone())
                      .eq(AudioManagement::getServiceStatus,  AudioManagementConstants.SERVICE_STATUS_IN_SERVICE)
                      .orderByDesc(AudioManagement::getCreateTime); // 按创建时间倒序
            
            List<AudioManagement> audioList = serviceManager.getAudioManagementService().list(audioQuery);
            
            // 检查audioList中updateTime大于12小时的记录，更新serviceStatus为"服务结束" ， 更新录音总时长
            if (audioList != null && !audioList.isEmpty()) {
                LocalDateTime now = LocalDateTime.now();
                for (AudioManagement audio : audioList) {
                    if (audio.getUpdateTime() != null) {
                        // 计算时间差（天数）
                        long daysBetween = ChronoUnit.HOURS.between(audio.getUpdateTime(), now);
                        if (daysBetween >= 12) {
                            LambdaQueryWrapper<AudioManagementSegments> audioQuery2 = new LambdaQueryWrapper<>();
                            audioQuery2.eq(AudioManagementSegments::getParentId, audio.getId()) ; // 关联这个id的所有录音片段
                            List<AudioManagementSegments> segmentsList = audioManagementSegmentsService.list(audioQuery2);
                            BigDecimal total = new BigDecimal(0);
                            segmentsList.forEach(segment2 ->{ //计算录音时长
                                total.add(segment2.getDuration());//分钟
                            });

                            audio.setServiceStatus(AudioManagementConstants.SERVICE_STATUS_SERVICE_FINISH_SYS);
                            audio.setDuration(total);
                            audio.setScenario(deviceManagement.getScenario());
                            serviceManager.getAudioManagementService().updateById(audio);
                            log.info("更新audio_management记录状态为服务结束，ID: {}, updateTime: {}, 距离现在: {}小时",
                                    audio.getId(), audio.getUpdateTime(), daysBetween);
                        }
                    }
                }
            }
            audioList = serviceManager.getAudioManagementService().list(audioQuery);
            String audioManagementId;
            if (audioList == null || audioList.isEmpty()) {
                // 如果没找到，插入一条新记录
                audioManagementId = createNewAudioManagement(deviceManagement);
                log.info("创建新的audio_management记录，ID: {} ",
                        audioManagementId );
            } else {
                // 如果找到（一条或多条），取最新的一条记录
                audioManagementId = audioList.get(0).getId();
                for (AudioManagement audio : audioList) {

                    // 计算录音总时长,   根据每段录音的时长加在一起。
                    LambdaQueryWrapper<AudioManagementSegments> audioQuery2 = new LambdaQueryWrapper<>();
                    audioQuery2.eq(AudioManagementSegments::getParentId, audio.getId()) ; // 关联这个id的所有录音片段
                    List<AudioManagementSegments> segmentsList = audioManagementSegmentsService.list(audioQuery2);
                    BigDecimal total = new BigDecimal(0);
                    segmentsList.forEach(segment2 ->{ //计算录音时长
                        total.add(segment2.getDuration());//分钟
                    });

                    if (!audio.getId().equals(audioManagementId) ) {//  除了最新的记录，其他记录的service_status改为"服务结束"
                        audio.setServiceStatus(AudioManagementConstants.SERVICE_STATUS_SERVICE_FINISH_SYS);
                        audio.setUpdateTime(LocalDateTime.now());
                        audio.setDuration(total);
                        audio.setScenario(deviceManagement.getScenario());
                        serviceManager.getAudioManagementService().updateById(audio);
                    }
                }
                log.info("找到audio_management记录，ID: {} , 共{}条记录",
                        audioManagementId , audioList.size());
            }
            
            // 将id设置到requestBody
            if (audioManagementId != null) {
                requestBody.put("audioManagementId", audioManagementId);
                log.info("设置audioManagementId到requestBody: {}", audioManagementId);
            }
            
        } catch (Exception e) {
            log.error("关联audio_management表失败", e);
            // 即使关联失败，也不影响后续处理，只记录日志
        } finally {
            // 恢复原来的租户ID
            if (originalTenantId != null) {
                TenantContextHolder.setTenantId(originalTenantId);
            } else {
                TenantContextHolder.clear();
            }
        }
    }
    
    /**
     * 创建新的audio_management记录
     * 
     * @param deviceManagement 设备管理信息
     * @return 新创建的记录ID
     */
    private String createNewAudioManagement(DeviceManagement deviceManagement) {
        AudioManagement newAudio = new AudioManagement();
        newAudio.setId(UUID.randomUUID().toString());
        newAudio.setRecordingName("服务中录音"); // 设置默认录音名称
        newAudio.setSalesName(deviceManagement.getSalesName());
        newAudio.setSalesPhone(deviceManagement.getSalesPhone());
        newAudio.setTenantId(deviceManagement.getTenantId()); // 租户id
        newAudio.setDealershipName(deviceManagement.getDealershipName());
        newAudio.setDealershipId(deviceManagement.getDealershipId());
        newAudio.setServiceStatus(AudioManagementConstants.SERVICE_STATUS_IN_SERVICE);
        newAudio.setScenario(deviceManagement.getScenario());
        newAudio.setCreateTime(TimeZoneUtils.now());
        newAudio.setUpdateTime(TimeZoneUtils.now());
        
        serviceManager.getAudioManagementService().save(newAudio);
        return newAudio.getId();
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }
        
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
            return fileName.substring(lastDotIndex + 1);
        }
        
        return "";
    }

    /**
     * 获取Content-Type
     */
    private String getContentType(String fileName) {
        String extension = getFileExtension(fileName).toLowerCase();
        
        switch (extension) {
            case "mp3":
                return "audio/mpeg";
            case "wav":
                return "audio/wav";
            case "m4a":
                return "audio/mp4";
            case "aac":
                return "audio/aac";
            case "ogg":
                return "audio/ogg";
            case "flac":
                return "audio/flac";
            case "wma":
                return "audio/x-ms-wma";
            default:
                return "application/octet-stream";
        }
    }
    
    /**
     * 处理Audio数据类型（录音推送） ，验证文件、保存文件到本地、保存信息到数据库
     * 适配新的数据结构：dataType="Audio"，数据在data字段中
     * 同时兼容旧的数据结构（数据直接在requestBody中）
     * 
     * @param requestBody 请求体数据
     * @param file 上传的音频文件
     * @return 处理结果，包含success、message、localFilePath等
     */
    private Map<String, Object> handleAudioDataType(Map<String, Object> requestBody, MultipartFile file) {
        log.info("开始处理Audio数据类型（录音推送）");
        
        try {
            // 1. 提取并解析data字段（新数据结构）
            Map<String, Object> dataFromDataField = extractDataField(requestBody);
            
            // 2. 判断使用新数据结构还是旧数据结构  ,  保存文件到本地 ，记录到数据库
            if (isLegacyDataStructure(dataFromDataField)) {
                log.info("检测到旧数据结构，验证文件、保存文件到本地、保存信息到数据库, 使用requestBody作为processedData");
                String deviceNo = extractStringField(requestBody, "deviceNo");
                String filePath = extractStringField(requestBody, "filePath");
                return handleAudioUpload(requestBody, requestBody, file, deviceNo, filePath);
            }
            
            // 3. 使用新数据结构处理  验证文件、保存文件到本地、保存信息到数据库
            log.info("检测到新数据结构，验证文件、保存文件到本地、保存信息到数据库 ");
            return processNewAudioData(requestBody, dataFromDataField, file);
            
        } catch (Exception e) {
            log.error("处理Audio数据类型异常", e);
            return createErrorResult("处理Audio数据类型异常: " + e.getMessage());
        }
    }
    
    /**
     * 从requestBody中提取data字段并转换为Map
     * 
     * @param requestBody 请求体数据
     * @return data字段转换后的Map，如果不存在或转换失败则返回null
     */
    private Map<String, Object> extractDataField(Map<String, Object> requestBody) {
        if (requestBody == null) {
            return null;
        }
        
        Object dataObj = requestBody.get("data");
        if (dataObj == null) {
            return null;
        }
        
        try {
            Map<String, Object> dataMap = objectMapper.convertValue(
                dataObj, 
                new TypeReference<Map<String, Object>>() {}
            );
            return dataMap;
        } catch (Exception e) {
            log.warn("解析data字段失败，可能不是Map类型: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 判断是否为旧的数据结构
     * 旧数据结构：data字段不存在或为空
     * 新数据结构：data字段存在且不为空
     * 
     * @param dataFromDataField 从data字段提取的数据
     * @return true表示旧数据结构，false表示新数据结构
     */
    private boolean isLegacyDataStructure(Map<String, Object> dataFromDataField) {
        return dataFromDataField == null || dataFromDataField.isEmpty();
    }
    
    /**
     * 处理旧数据结构的Audio数据
     * 旧数据结构：数据直接在requestBody中，没有data字段
     * 
     * @param requestBody 请求体数据（同时作为processedData）
     * @param file 上传的音频文件
     * @return 处理结果
     */
//    private Map<String, Object> processLegacyAudioData(Map<String, Object> requestBody, MultipartFile file) {
//        String deviceNo = extractStringField(requestBody, "deviceNo");
//        String filePath = extractStringField(requestBody, "filePath");
//
//        return handleAudioUpload(requestBody, requestBody, file, deviceNo, filePath);
//    }
    
    /**
     * 处理新数据结构的Audio数据
     * 新数据结构：数据在data字段中，requestBody中可能还有其他字段（如deviceNo、filePath等）
     * 
     * @param requestBody 请求体数据
     * @param dataFromDataField 从data字段提取的数据
     * @param file 上传的音频文件
     * @return 处理结果
     */
    private Map<String, Object> processNewAudioData(Map<String, Object> requestBody, 
                                                     Map<String, Object> dataFromDataField, 
                                                     MultipartFile file) {
        // 构建processedData：以data字段中的数据为主
        Map<String, Object> processedData = new HashMap<>(dataFromDataField);
        
        // 提取关键字段：优先使用requestBody中的字段，如果不存在则使用data字段中的
        String deviceNo = extractStringField(requestBody, "deviceNo");
        String filePath = extractStringFieldWithFallback(requestBody, dataFromDataField, "filePath");
        
        return handleAudioUpload(requestBody, processedData, file, deviceNo, filePath);
    }
    
    /**
     * 从Map中提取String类型字段
     * 
     * @param map 数据Map
     * @param fieldName 字段名
     * @return 字段值，如果不存在或类型不匹配则返回null
     */
    private String extractStringField(Map<String, Object> map, String fieldName) {
        if (map == null || fieldName == null) {
            return null;
        }
        
        Object value = map.get(fieldName);
        if (value == null) {
            return null;
        }
        
        return value.toString();
    }
    
    /**
     * 从Map中提取String类型字段，如果不存在则从fallbackMap中获取
     * 
     * @param primaryMap 优先使用的Map
     * @param fallbackMap 备用Map
     * @param fieldName 字段名
     * @return 字段值，如果都不存在则返回null
     */
    private String extractStringFieldWithFallback(Map<String, Object> primaryMap, 
                                                   Map<String, Object> fallbackMap, 
                                                   String fieldName) {
        // 优先从primaryMap中获取
        String value = extractStringField(primaryMap, fieldName);
        if (value != null) {
            return value;
        }
        
        // 如果primaryMap中没有，从fallbackMap中获取
        return extractStringField(fallbackMap, fieldName);
    }
    
    /**
     * 从 audioFileOriginalName 中提取特数字字符串A
     * 截取规则：
     * 1. 找到 "-Z0" 或 "-A0" 之后的字符串B
     * 2. 从字符串B中截取 "-00" 之前的字符串，这就是特数字字符串A
     * 
     * @param originalName 原始文件名
     * @return 特数字字符串A，如果无法提取则返回null
     */
    private String extractSpecialNumberA(String originalName) {
        if (originalName == null || originalName.trim().isEmpty()) {
            return null;
        }
        
        // 查找 "-Z0" 或 "-A0" 的位置
        int z0Index = originalName.indexOf("-Z0");
        int a0Index = originalName.indexOf("-A0");
        
        int startIndex = -1;
        if (z0Index != -1) {
            startIndex = z0Index + 3; // "-Z0" 长度为3
        } else if (a0Index != -1) {
            startIndex = a0Index + 3; // "-A0" 长度为3
        }
        
        if (startIndex == -1 || startIndex >= originalName.length()) {
            return null;
        }
        
        // 获取 "-Z0" 或 "-A0" 之后的字符串B
        String stringB = originalName.substring(startIndex);
        
        // 从字符串B中截取 "-00" 之前的字符串
        int dash00Index = stringB.indexOf("-00");
        if (dash00Index == -1) {
            // 如果没有找到 "-00"，返回整个字符串B
            return stringB.trim().isEmpty() ? null : stringB.trim();
        }
        
        String specialNumberA = stringB.substring(0, dash00Index);
        return specialNumberA.trim().isEmpty() ? null : specialNumberA.trim();
    }
    
    /**
     * 检查是否满足设置服务状态为"服务结束"的条件
     * 需要同时满足两个条件：
     * 1. 所有 audioFileOriginalName 拼接后同时包含 "-Z0" 和 "-A0"
     * 2. 从所有 audioFileOriginalName 中提取的特数字字符串A转换为数字后，排序后相邻数字相差1
     * 
     * @param allSegments 所有音频分段记录列表
     * @return 如果两个条件都满足返回true，否则返回false
     */
    private boolean checkServiceFinishConditions(List<AudioManagementSegments> allSegments) {
        if (allSegments == null || allSegments.isEmpty()) {
            return false;
        }
        if (allSegments.size()==1){
            String audioFileOriginalName = allSegments.get(0).getAudioFileOriginalName();
             if (audioFileOriginalName.contains("-Z0")){
                 return true;
             }
        }

        // 条件1：将所有 audioFileOriginalName 拼接，检查是否同时包含 "-Z0" 和 "-A0"
        StringBuilder concatenatedNames = new StringBuilder();
        for (AudioManagementSegments seg : allSegments) {
            if (seg.getAudioFileOriginalName() != null) {
                concatenatedNames.append(seg.getAudioFileOriginalName());
            }
        }
        String allNames = concatenatedNames.toString();
        boolean condition1 = allNames.contains("-Z0") && allNames.contains("-A0");
        
        if (!condition1) {
            log.debug("条件1不满足：未同时包含 '-Z0' 和 '-A0'");
            return false;
        }
        
        // 条件2：提取特数字字符串A，转换为数字后排序，检查相邻数字是否相差1
        List<Integer> numberList = new ArrayList<>();
        for (AudioManagementSegments seg : allSegments) {
            String originalName = seg.getAudioFileOriginalName();
            if (originalName != null && !originalName.trim().isEmpty()) {
                String specialNumberA = extractSpecialNumberA(originalName);
                if (specialNumberA != null && !specialNumberA.trim().isEmpty()) {
                    try {
                        int number = Integer.parseInt(specialNumberA);
                        numberList.add(number);
                    } catch (NumberFormatException e) {
                        log.debug("无法将特数字字符串转换为数字: {}", specialNumberA);
                    }
                }
            }
        }

        Collections.sort(numberList);
        for (int i = 1; i < numberList.size(); i++) {
            if (numberList.get(i) - numberList.get(i - 1) != 1) {
                log.debug("条件2不满足：相邻数字相差不为1，数字列表: {}", numberList);
                return false;
            }
        }
        
        log.debug("两个条件都满足，可以设置服务状态为服务结束");
        return true;
    }
    
    /**
     * 处理Gps数据类型（GPS日志）
     */
    private Map<String, Object> handleGpsDataType(Map<String, Object> requestBody) {
        Map<String, Object> result = new HashMap<>();
        log.info("GPS日志处理功能待实现，数据: {}", requestBody);
        result.put("success", true);
        result.put("message", "GPS日志接收成功（处理功能待实现）");
        return result;
    }
    
    /**
     * 处理AudioText数据类型（语音转写）
     * 根据deviceNo和filename查询并更新audio_management_segments表的recording_text字段
     * recording_text的值等于所有segments中text字段的累加
     */
    private Map<String, Object> handleAudioTextDataType(Map<String, Object> requestBody) {
        log.info("开始处理AudioText数据类型（语音转写）");
        
        try {
            // 1. 提取data字段
            Map<String, Object> dataMap = extractDataField(requestBody);
            if (dataMap == null || dataMap.isEmpty()) {
                log.warn("AudioText数据中data字段为空或不存在");
                return createErrorResult("AudioText数据中data字段为空或不存在");
            }
            
            // 2. 提取deviceNo和filename
            String deviceNo = extractStringFieldWithFallback(requestBody, dataMap, "deviceNo");
            String filename = extractStringField(dataMap, "filename");
            
            if (deviceNo == null || deviceNo.trim().isEmpty()) {
                log.warn("AudioText数据中deviceNo字段为空");
                return createErrorResult("AudioText数据中deviceNo字段为空");
            }
            
            if (filename == null || filename.trim().isEmpty()) {
                log.warn("AudioText数据中filename字段为空");
                return createErrorResult("AudioText数据中filename字段为空");
            }
            
            log.info("处理语音转写数据，deviceNo: {}, filename: {}", deviceNo, filename);
            
            // 3. 提取segments数组
            Object segmentsObj = dataMap.get("segments");
            if (segmentsObj == null) {
                log.warn("AudioText数据中segments字段为空");
                return createErrorResult("AudioText数据中segments字段为空");
            }
            
            // 4. 解析segments并累加text字段
            List<Map<String, Object>> segmentsList;
            try {
                segmentsList = objectMapper.convertValue(segmentsObj, 
                    new TypeReference<List<Map<String, Object>>>() {});
            } catch (Exception e) {
                log.error("解析segments字段失败", e);
                return createErrorResult("解析segments字段失败: " + e.getMessage());
            }
            
            if (segmentsList == null || segmentsList.isEmpty()) {
                log.warn("AudioText数据中segments数组为空");
                return createErrorResult("AudioText数据中segments数组为空");
            }
            
            // 5. 累加所有segments中的text字段
            StringBuilder recordingTextBuilder = new StringBuilder();
            for (Map<String, Object> segment : segmentsList) {
                Object textObj = segment.get("text");
                if (textObj != null) {
                    String text = textObj.toString().trim();
                    if (!text.isEmpty()) {
                        if (recordingTextBuilder.length() > 0) {
                            recordingTextBuilder.append(" ");
                        }
                        recordingTextBuilder.append(text);
                    }
                }
            }
            
            String recordingText = recordingTextBuilder.toString();
            log.info("累加的录音文本长度: {} 字符", recordingText.length());
            
            // 6. 获取DeviceManagement和tenantId（参考插入时的处理逻辑）
            DeviceManagement deviceManagement = (DeviceManagement) requestBody.get(deviceKey);
            
            // 如果requestBody中没有DeviceManagement，则根据deviceNo查询
            if (deviceManagement == null) {
                try {
                    deviceManagement = deviceManagementMapper.selectByDeviceCodeIgnoreTenant(deviceNo);
                    if (deviceManagement != null) {
                        requestBody.put(deviceKey, deviceManagement);
                        log.info("根据设备编号 {} 查询到DeviceManagement", deviceNo);
                    }
                } catch (Exception e) {
                    log.warn("查询DeviceManagement失败，设备编号: {}", deviceNo, e);
                }
            }
            
            // 7. 设置租户ID到上下文，使后续查询自动使用该租户ID（参考associateAudioManagement的处理逻辑）
            String originalTenantId = TenantContextHolder.getTenantId();
            String tenantId = null;
            
            if (deviceManagement != null && deviceManagement.getTenantId() != null) {
                tenantId = deviceManagement.getTenantId();
                TenantContextHolder.setTenantId(tenantId);
                log.info("设置租户ID到上下文: {}", tenantId);
            } else {
                log.warn("deviceManagement为空或tenantId为空，无法设置租户上下文");
            }
            
            try {
                // 8. 根据filename直接更新audio_management_segments表的recording_text字段
                // 注意：不手动添加tenant_id条件，让多租户拦截器自动添加
                AudioManagementSegments updateEntity = new AudioManagementSegments();
                updateEntity.setRecordingText(recordingText);
                
                LambdaUpdateWrapper<AudioManagementSegments> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(AudioManagementSegments::getAudioFileOriginalName, filename);

                boolean updateResult = audioManagementSegmentsService.update(updateEntity, updateWrapper);
                
                if (updateResult) {
                    log.info("成功更新录音文本，deviceNo: {}, filename: {}", deviceNo, filename);
                    
                    // 根据 audioFileOriginalName 查询记录，获取 parentId
                    LambdaQueryWrapper<AudioManagementSegments> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(AudioManagementSegments::getAudioFileOriginalName, filename);
                    List<AudioManagementSegments> segmentsByFilename = audioManagementSegmentsService.list(queryWrapper);
                    
                    if (!segmentsByFilename.isEmpty() && segmentsByFilename.get(0).getParentId() != null) {
                        String parentId = segmentsByFilename.get(0).getParentId();
                        
                        // 根据 parentId 查询所有 audio_management_segments 记录
                        LambdaQueryWrapper<AudioManagementSegments> parentQueryWrapper = new LambdaQueryWrapper<>();
                        parentQueryWrapper.eq(AudioManagementSegments::getParentId, parentId)
                                         .orderByAsc(AudioManagementSegments::getChunkIndex); // 按 chunkIndex 排序
                        List<AudioManagementSegments> allSegments = audioManagementSegmentsService.list(parentQueryWrapper);
                        
                        // 检查每条记录的 recordingText 是否都不为空，并拼接
                        boolean allHaveText = true;
                        StringBuilder concatenatedText = new StringBuilder();
                        
                        for (AudioManagementSegments segment : allSegments) {
                            String segmentText = segment.getRecordingText();
                            if (segmentText == null || segmentText.trim().isEmpty()) {
                                allHaveText = false;
                                break;
                            }
                            if (concatenatedText.length() > 0) {
                                concatenatedText.append(" ======");
                            }
                            concatenatedText.append(segmentText);
                        }
                        
                        // 如果每条记录的 recordingText 都不为空，更新 audio_management 的 recording_text
                        if (allHaveText && concatenatedText.length() > 0) {
                            AudioManagement audioManagement = new AudioManagement();
                            audioManagement.setId(parentId);
                            audioManagement.setRecordingText(concatenatedText.toString());
                            audioManagement.setUpdateTime(LocalDateTime.now());
                            if (deviceManagement != null) {
                                audioManagement.setScenario(deviceManagement.getScenario());
                            }

                            boolean updateAudioManagementResult = serviceManager.getAudioManagementService().updateById(audioManagement);
                            if (updateAudioManagementResult) {
                                log.info("成功更新AudioManagement的recordingText，parentId: {}, 拼接文本长度: {}", 
                                        parentId, concatenatedText.length());
                            } else {
                                log.warn("更新AudioManagement的recordingText失败，parentId: {}", parentId);
                            }
                        } else {
                            log.info("部分segment的recordingText为空，暂不更新AudioManagement的recordingText，parentId: {}", parentId);
                        }
                    } else {
                        log.warn("未找到匹配的AudioManagementSegments记录或parentId为空，filename: {}", filename);
                    }
                    
                    Map<String, Object> result = new HashMap<>();
                    result.put("success", true);
                    result.put("message", "语音转写数据更新成功");
                    result.put("recordingTextLength", recordingText.length());
                    return result;
                } else {
                    log.warn("更新录音文本失败，deviceNo: {}, filename: {}", deviceNo, filename);
                    return createErrorResult("更新录音文本失败，可能未找到匹配的记录");
                }
            } finally {
                // 恢复原来的租户ID
                if (originalTenantId != null) {
                    TenantContextHolder.setTenantId(originalTenantId);
                } else {
                    TenantContextHolder.clear();
                }
            }
            
        } catch (Exception e) {
            log.error("处理AudioText数据类型异常", e);
            return createErrorResult("处理AudioText数据类型异常: " + e.getMessage());
        }
    }
    
    /**
     * 处理LoginLog数据类型（登录日志）
     */
    private Map<String, Object> handleLoginLogDataType(Map<String, Object> requestBody) {
        Map<String, Object> result = new HashMap<>();
        log.info("登录日志处理功能待实现，数据: {}", requestBody);
        result.put("success", true);
        result.put("message", "登录日志接收成功（处理功能待实现）");
        return result;
    }
    
    /**
     * 处理ControlLog数据类型（操控日志）
     */
    private Map<String, Object> handleControlLogDataType(Map<String, Object> requestBody) {
        Map<String, Object> result = new HashMap<>();
        log.info("操控日志处理功能待实现，数据: {}", requestBody);
        result.put("success", true);
        result.put("message", "操控日志接收成功（处理功能待实现）");
        return result;
    }
    
    /**
     * 处理UploadLog数据类型（上传日志）
     * 适配新的数据结构：dataType="UploadLog"，数据在data字段中
     * 功能：保存文件到本地（如果有），写入yhy_audio_upload_log表
     */
    private Map<String, Object> handleUploadLogDataType(Map<String, Object> requestBody, MultipartFile file) {
        Map<String, Object> result = new HashMap<>();
        
            log.info("处理UploadLog数据类型（上传日志）");
            return  result;
    }
    
    /**
     * 保存上传日志到数据库
     * 
     * @param requestBody 请求体数据
     * @param processedData 处理后的数据（从data字段解析）
     * @param localFilePath 本地文件路径（如果文件已保存）
     * @param file 上传的文件（可能为null）
     * @param deviceNo 设备号
     */
    private void saveUploadLogToDatabase(Map<String, Object> requestBody, 
                                         Map<String, Object> processedData,
                                         String localFilePath,
                                         MultipartFile file,
                                         String deviceNo) {
        try {
            YhyAudioUploadLog audioUploadLog = new YhyAudioUploadLog();
            audioUploadLog.setId(UUID.randomUUID().toString());
            
            // 从requestBody中提取数据
            audioUploadLog.setFilePath((String) requestBody.get("filePath"));
            audioUploadLog.setContentType((String) requestBody.get("contentType"));
            audioUploadLog.setDeviceNo(deviceNo);
            audioUploadLog.setServerUrl((String) requestBody.get("serverUrl"));
            audioUploadLog.setPushDataType("UploadLog");
            
            // 从processedData中提取数据（data字段中的内容）
            if (processedData != null) {
                audioUploadLog.setFileName((String) processedData.get("fileName"));
                audioUploadLog.setSavePath((String) processedData.get("savePath"));
                audioUploadLog.setChunkIndex((String) processedData.get("chunkIndex"));
                audioUploadLog.setStartTime((String) processedData.get("startTime"));
                audioUploadLog.setEndTime((String) processedData.get("endTime"));
                audioUploadLog.setUsrNo((String) processedData.get("usrNo"));
                audioUploadLog.setDeviceType((String) processedData.get("deviceType"));
                
                // 处理hasBody字段
                Object hasBodyObj = processedData.get("hasBody");
                if (hasBodyObj != null) {
                    if (hasBodyObj instanceof Boolean) {
                        audioUploadLog.setHasBody((Boolean) hasBodyObj);
                    } else if (hasBodyObj instanceof String) {
                        audioUploadLog.setHasBody(Boolean.parseBoolean((String) hasBodyObj));
                    }
                }
                
                // 处理extended字段（JSON格式），包含realStartTime、realEndTime、lengthBytes、createdTime等
                Map<String, Object> extendedMap = new HashMap<>();
                if (processedData.get("realStartTime") != null) {
                    extendedMap.put("realStartTime", processedData.get("realStartTime"));
                }
                if (processedData.get("realEndTime") != null) {
                    extendedMap.put("realEndTime", processedData.get("realEndTime"));
                }
                if (processedData.get("lengthBytes") != null) {
                    extendedMap.put("lengthBytes", processedData.get("lengthBytes"));
                }
                if (processedData.get("createdTime") != null) {
                    extendedMap.put("createdTime", processedData.get("createdTime"));
                }
                // 如果有其他扩展字段，也添加到extended中
                if (!extendedMap.isEmpty()) {
                    try {
                        audioUploadLog.setExtended(objectMapper.writeValueAsString(extendedMap));
                    } catch (Exception e) {
                        log.warn("序列化extended字段失败", e);
                    }
                }
                
                audioUploadLog.setUserId((String) processedData.get("userId"));
                audioUploadLog.setUserName((String) processedData.get("userName"));
                audioUploadLog.setUserPhone((String) processedData.get("userPhone"));
                audioUploadLog.setUserDept((String) processedData.get("userDept"));
            }
            
            // 设置本地文件路径（如果文件已保存）
            if (localFilePath != null && !localFilePath.isEmpty()) {
                // 如果savePath为空，使用localFilePath的目录部分
                if (audioUploadLog.getSavePath() == null || audioUploadLog.getSavePath().isEmpty()) {
                    int lastSeparator = localFilePath.lastIndexOf(File.separator);
                    if (lastSeparator > 0) {
                        audioUploadLog.setSavePath(localFilePath.substring(0, lastSeparator));
                    }
                }
            }
            
            // 设置同步阶段（初始状态）
            audioUploadLog.setSyncStage("已上传");
            
            // 设置关联的录音管理ID（如果存在）
            Object audioManagementIdObj = requestBody.get("audioManagementId");
            if (audioManagementIdObj != null) {
                audioUploadLog.setAudioManagementId(audioManagementIdObj.toString());
                log.info("设置audioManagementId到音频上传日志: {}", audioManagementIdObj);
            }
            
            // 设置创建和更新时间（使用配置的时区）
            LocalDateTime now = TimeZoneUtils.now();
            audioUploadLog.setCreateTime(now);
            audioUploadLog.setUpdateTime(now);
            
            // 保存到数据库
            yhyAudioUploadLogService.save(audioUploadLog);
            log.info("上传日志保存成功，ID: {}, 设备号: {}, 文件名: {}", 
                    audioUploadLog.getId(), audioUploadLog.getDeviceNo(), audioUploadLog.getFileName());
            
        } catch (Exception e) {
            log.error("保存上传日志到数据库失败", e);
            throw new RuntimeException("保存上传日志失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 处理DebugLog数据类型（运行日志）
     */
    private Map<String, Object> handleDebugLogDataType(Map<String, Object> requestBody) {
        Map<String, Object> result = new HashMap<>();
        log.info("运行日志处理功能待实现，数据: {}", requestBody);
        result.put("success", true);
        result.put("message", "运行日志接收成功（处理功能待实现）");
        return result;
    }
    
    /**
     * 处理MergeAudio数据类型（合并录音）
     */
    private Map<String, Object> handleMergeAudioDataType(Map<String, Object> requestBody) {
        Map<String, Object> result = new HashMap<>();
        log.info("合并录音处理功能待实现，数据: {}", requestBody);
        result.put("success", true);
        result.put("message", "合并录音接收成功（处理功能待实现）");
        return result;
    }
    
    /**
     * 保存数据到 yhy_datatype_log 表
     * 将接收到的所有数据进行初步解析后保存
     * 
     * @param headers 请求头信息
     * @param requestBody 请求体数据
     */
    private void saveDatatypeLog(Map<String, String> headers, Map<String, Object> requestBody) {
        try {
            YhyDatatypeLog datatypeLog = new YhyDatatypeLog();
            datatypeLog.setId(UUID.randomUUID().toString());
            
            // 提取 dataType（优先使用 dataType，兼容 pushDataType）
            String dataType = null;
            if (requestBody != null) {
                dataType = (String) requestBody.get("dataType");
                if (dataType == null || dataType.trim().isEmpty()) {
                    dataType = (String) requestBody.get("pushDataType");
                }
            }
            
            // 如果 dataType 仍为 null，根据请求头或请求内容推断默认值
            if (dataType == null || dataType.trim().isEmpty()) {
                // 根据 content-type 判断请求类型
                if (headers != null) {
                    String contentType = headers.get("content-type");
                    if (contentType != null) {
                        if (contentType.toLowerCase().contains("multipart/form-data")) {
                            // 文件上传请求
                            dataType = "UploadLog";
                        } else if (contentType.toLowerCase().contains("application/json")) {
                            // JSON 请求
                            dataType = "DataLog";
                        } else {
                            // 其他类型
                            dataType = "Unknown";
                        }
                    } else {
                        // 没有 content-type，使用默认值
                        dataType = "Unknown";
                    }
                } else {
                    // 没有 headers，使用默认值
                    dataType = "Unknown";
                }
            }
            
            datatypeLog.setDataType(dataType);
            
            // 提取 deviceNo
            String deviceNo = null;
            if (requestBody != null) {
                deviceNo = (String) requestBody.get("deviceNo");
            }
            datatypeLog.setDeviceNo(deviceNo);
            
            // 将 headers 和 requestBody 合并序列化为 JSON 字符串保存到 contents
            Map<String, Object> contentsMap = new HashMap<>();
            if (headers != null && !headers.isEmpty()) {
                contentsMap.put("headers", headers);
            }
            if (requestBody != null && !requestBody.isEmpty()) {
                contentsMap.put("body", requestBody);
            }
            
            String contentsJson = objectMapper.writeValueAsString(contentsMap);
            datatypeLog.setContents(contentsJson);
            
            // 设置创建和更新时间（使用配置的时区）
            LocalDateTime now = TimeZoneUtils.now();
            datatypeLog.setCreateTime(now);
            datatypeLog.setUpdateTime(now);
            
            // 保存到数据库
            yhyDatatypeLogService.save(datatypeLog);
            log.info("数据已保存到yhy_datatype_log表，ID: {}, 数据类型: {}, 设备号: {}", 
                    datatypeLog.getId(), dataType, deviceNo);
            
        } catch (Exception e) {
            log.error("保存数据到yhy_datatype_log表异常", e);
            throw new RuntimeException("保存数据到yhy_datatype_log表失败: " + e.getMessage(), e);
        }
    }
}
