package com.aiotagro.cattletrade.business.controller;


import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.dto.DeliverListDto;
import com.aiotagro.cattletrade.business.dto.DeliveryAddDto;
import com.aiotagro.cattletrade.business.dto.DeliveryCreateDto;
import com.aiotagro.cattletrade.business.dto.DeliveryEditDto;
import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.dto.DeliveryTrackQueryDto;
import com.aiotagro.cattletrade.business.dto.DeviceAssignDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.entity.JbqClient;
import com.aiotagro.cattletrade.business.entity.XqClient;
import com.aiotagro.cattletrade.business.service.BaiduYingyanService;
import com.aiotagro.cattletrade.business.service.IDeliveryService;
import com.aiotagro.cattletrade.business.service.IDeliveryDeviceService;
import com.aiotagro.cattletrade.business.service.IJbqClientService;
import com.aiotagro.cattletrade.business.service.IXqClientService;
import com.aiotagro.common.core.context.SecurityContextHolder;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.aiotagro.common.core.constant.RoleConstants;
import com.aiotagro.common.core.constant.TencentCloudConstants;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.model.GetObjectRequest;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.aiotagro.cattletrade.business.mapper.MemberMapper;
import com.aiotagro.cattletrade.business.mapper.OrderMapper;
import com.aiotagro.cattletrade.business.entity.Order;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 运送清单表 前端控制器
 *
 * @author admin
 * @since 2024-12-26
 */
@RestController
@RequestMapping("/delivery")
public class DeliveryController {
    
    private static final Logger logger = LoggerFactory.getLogger(DeliveryController.class);

    @Autowired
    private IDeliveryService deliveryService;

    @Autowired
    private IDeliveryDeviceService deliveryDeviceService;
    
    @Autowired
    private IJbqClientService jbqClientService;
    
    @Autowired
    private IXqClientService xqClientService;
    
    @Autowired
    private com.aiotagro.cattletrade.business.mapper.IotDeviceDataMapper iotDeviceDataMapper;
    
    @Autowired
    private MemberMapper memberMapper;
    
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private BaiduYingyanService baiduYingyanService;



    /**
     * 小程序运送清单-分页查询
     *
     * @param dto
     * @return
     */
    @SaCheckPermission("delivery:list")
    @PostMapping(value = "/pageQuery")
    public PageResultResponse<Delivery> pageQuery(@RequestBody DeliveryQueryDto dto) {
        return deliveryService.pageQuery(dto);
    }

    /**
     * 小程序运送清单-我要装车
     * @param dto
     * @return
     */
    @SaCheckPermission("delivery:add")
    @PostMapping(value = "/add")
    public AjaxResult add(@RequestBody DeliveryAddDto dto) {
        try{
           return deliveryService.addDelivery(dto);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 运送清单-创建（PC端新增接口）
     * @param dto
     * @return
     */
    @SaCheckPermission("delivery:add")
    @PostMapping(value = "/create")
    public AjaxResult create(@Validated @RequestBody DeliveryCreateDto dto) {
        try{
           return deliveryService.createDelivery(dto);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 装车订单-新增（PC端装车订单创建接口）
     * @param params
     * @return
     */
    @SaCheckPermission("delivery:add")
    @PostMapping(value = "/addDeliveryOrder")
    public AjaxResult addDeliveryOrder(@RequestBody Map<String, Object> params) {
        try {
            // 获取参数值
            String deliveryTitle = (String) params.get("deliveryTitle");
            Integer ratedQuantity = null;
            if (params.get("ratedQuantity") != null) {
                Object ratedQuantityObj = params.get("ratedQuantity");
                if (ratedQuantityObj instanceof Integer) {
                    ratedQuantity = (Integer) ratedQuantityObj;
                } else if (ratedQuantityObj instanceof String) {
                    try {
                        ratedQuantity = Integer.parseInt((String) ratedQuantityObj);
                    } catch (NumberFormatException e) {
                        return AjaxResult.error("装车数量格式不正确");
                    }
                }
            }
            
            String supplierId = (String) params.get("supplierId");
            
            Integer fundId = null;
            if (params.get("fundId") != null) {
                Object fundIdObj = params.get("fundId");
                if (fundIdObj instanceof Integer) {
                    fundId = (Integer) fundIdObj;
                } else if (fundIdObj instanceof String) {
                    try {
                        fundId = Integer.parseInt((String) fundIdObj);
                    } catch (NumberFormatException e) {
                        return AjaxResult.error("资金方ID格式不正确");
                    }
                }
            }
            
            Integer driverId = null;
            if (params.get("driverId") != null) {
                Object driverIdObj = params.get("driverId");
                if (driverIdObj instanceof Integer) {
                    driverId = (Integer) driverIdObj;
                } else if (driverIdObj instanceof String) {
                    try {
                        driverId = Integer.parseInt((String) driverIdObj);
                    } catch (NumberFormatException e) {
                        return AjaxResult.error("司机ID格式不正确");
                    }
                }
            }
            
            Integer buyerId = null;
            if (params.get("buyerId") != null) {
                Object buyerIdObj = params.get("buyerId");
                if (buyerIdObj instanceof Integer) {
                    buyerId = (Integer) buyerIdObj;
                } else if (buyerIdObj instanceof String) {
                    try {
                        buyerId = Integer.parseInt((String) buyerIdObj);
                    } catch (NumberFormatException e) {
                        return AjaxResult.error("采购商ID格式不正确");
                    }
                }
            }
            
            Double buyerPrice = null;
            if (params.get("buyerPrice") != null) {
                Object buyerPriceObj = params.get("buyerPrice");
                if (buyerPriceObj instanceof Double) {
                    buyerPrice = (Double) buyerPriceObj;
                } else if (buyerPriceObj instanceof String) {
                    try {
                        buyerPrice = Double.parseDouble((String) buyerPriceObj);
                    } catch (NumberFormatException e) {
                        return AjaxResult.error("采购价格格式不正确");
                    }
                }
            }
            
            Double salePrice = null;
            if (params.get("salePrice") != null) {
                Object salePriceObj = params.get("salePrice");
                if (salePriceObj instanceof Double) {
                    salePrice = (Double) salePriceObj;
                } else if (salePriceObj instanceof String) {
                    try {
                        salePrice = Double.parseDouble((String) salePriceObj);
                    } catch (NumberFormatException e) {
                        return AjaxResult.error("销售价格格式不正确");
                    }
                }
            }
            
            Double firmPrice = null;
            if (params.get("firmPrice") != null) {
                Object firmPriceObj = params.get("firmPrice");
                if (firmPriceObj instanceof Double) {
                    firmPrice = (Double) firmPriceObj;
                } else if (firmPriceObj instanceof String) {
                    try {
                        firmPrice = Double.parseDouble((String) firmPriceObj);
                    } catch (NumberFormatException e) {
                        return AjaxResult.error("约定单价格式不正确");
                    }
                }
            }
            String startLocation = (String) params.get("startLocation");
            
            String startLat = null;
            if (params.get("startLat") != null) {
                Object startLatObj = params.get("startLat");
                if (startLatObj instanceof String) {
                    startLat = (String) startLatObj;
                } else if (startLatObj instanceof Double) {
                    startLat = String.valueOf((Double) startLatObj);
                } else if (startLatObj instanceof Integer) {
                    startLat = String.valueOf((Integer) startLatObj);
                }
            }
            
            String startLon = null;
            if (params.get("startLon") != null) {
                Object startLonObj = params.get("startLon");
                if (startLonObj instanceof String) {
                    startLon = (String) startLonObj;
                } else if (startLonObj instanceof Double) {
                    startLon = String.valueOf((Double) startLonObj);
                } else if (startLonObj instanceof Integer) {
                    startLon = String.valueOf((Integer) startLonObj);
                }
            }
            
            String endLocation = (String) params.get("endLocation");
            
            String endLat = null;
            if (params.get("endLat") != null) {
                Object endLatObj = params.get("endLat");
                if (endLatObj instanceof String) {
                    endLat = (String) endLatObj;
                } else if (endLatObj instanceof Double) {
                    endLat = String.valueOf((Double) endLatObj);
                } else if (endLatObj instanceof Integer) {
                    endLat = String.valueOf((Integer) endLatObj);
                }
            }
            
            String endLon = null;
            if (params.get("endLon") != null) {
                Object endLonObj = params.get("endLon");
                if (endLonObj instanceof String) {
                    endLon = (String) endLonObj;
                } else if (endLonObj instanceof Double) {
                    endLon = String.valueOf((Double) endLonObj);
                } else if (endLonObj instanceof Integer) {
                    endLon = String.valueOf((Integer) endLonObj);
                }
            }

            // 参数验证
            if (deliveryTitle == null || deliveryTitle.trim().isEmpty()) {
                return AjaxResult.error("订单标题不能为空");
            }
            if (ratedQuantity == null || ratedQuantity <= 0) {
                return AjaxResult.error("装车数量必须大于0");
            }
            if (startLocation == null || startLocation.trim().isEmpty()) {
                return AjaxResult.error("起始地不能为空");
            }
            if (endLocation == null || endLocation.trim().isEmpty()) {
                return AjaxResult.error("目的地不能为空");
            }

            // 获取当前登录用户
            Integer userId = SecurityUtil.getCurrentUserId();
            String userName = SecurityContextHolder.getUserName(); // 使用SecurityContextHolder获取用户名
            
            // 生成运输单号
            LocalDateTime now = LocalDateTime.now();
            String deliveryNumber = "ZC" + now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
            
            // 创建装车订单
            Delivery delivery = new Delivery();
            delivery.setDeliveryNumber(deliveryNumber);
            delivery.setDeliveryTitle(deliveryTitle);
            delivery.setRatedQuantity(ratedQuantity);
            delivery.setSupplierId(supplierId);
            delivery.setFundId(fundId);
            delivery.setDriverId(driverId);
            delivery.setBuyerId(buyerId);
            delivery.setBuyerPrice(buyerPrice);
            delivery.setSalePrice(salePrice);
            delivery.setFirmPrice(firmPrice);
            delivery.setStartLocation(startLocation);
            delivery.setStartLat(startLat);
            delivery.setStartLon(startLon);
            delivery.setEndLocation(endLocation);
            delivery.setEndLat(endLat);
            delivery.setEndLon(endLon);
            delivery.setStatus(1); // 待装车
            delivery.setCreatedBy(userId);
            delivery.setCreateByName(userName);
            delivery.setCreateTime(new Date());
            
            // 保存装车订单
            boolean saved = deliveryService.save(delivery);
            if (!saved) {
                return AjaxResult.error("创建装车订单失败");
            }
            
            return AjaxResult.success("装车订单创建成功");
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("创建装车订单失败：" + e.getMessage());
        }
    }

    /**
     * 运送清单-编辑（PC端编辑接口）
     * @param dto
     * @return
     */
    @SaCheckPermission("delivery:edit")
    @PostMapping(value = "/updateDeliveryInfo")
    public AjaxResult updateDeliveryInfo(@Validated @RequestBody DeliveryEditDto dto) {
        try{
           return deliveryService.updateDeliveryInfo(dto);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 小程序运送清单-查询详情
     * @param id
     * @return
     */
    @SaCheckPermission("delivery:view")
    @GetMapping(value = "/view")
    public AjaxResult view(@RequestParam Integer id) {
        return deliveryService.viewDelivery(id);
    }


    /**
     * 小程序运送清单-核验提交
     * @param delivery
     * @return
     */
    @SaCheckPermission("delivery:check")
    @PostMapping(value = "/submitCheck")
    public AjaxResult submitCheck(@RequestBody Delivery delivery) {
        try{
            //查询当前的登录用户，即核验人
            delivery.setCheckBy(SecurityUtil.getCurrentUserId());
            delivery.setCheckTime(new Date());
            delivery.setCheckByName(SecurityUtil.getUserName());
            boolean b = deliveryService.updateById(delivery);
            if(b){
                return AjaxResult.success("核验提交成功！");
            }else{
                return AjaxResult.error("核验提交失败！");
            }
        }catch (Exception e){
            return AjaxResult.error("核验提交失败！");
        }
    }

    /**
     * 后台系统运送清单-分页查询
     *
     * @param dto
     * @return
     */
    @SaCheckPermission("delivery:list")
    @PostMapping(value = "/pageQueryList")
    public PageResultResponse<Delivery> pageQueryList(@RequestBody DeliveryQueryDto dto) {
        return deliveryService.pageQuery(dto);
    }

    /**
     * 后台系统运送清单-分页查询（别名）
     *
     * @param dto
     * @return
     */
    @SaCheckPermission("delivery:list")
    @PostMapping(value = "/pageDeliveryOrderList")
    public PageResultResponse<Delivery> pageDeliveryOrderList(@RequestBody DeliverListDto dto) {
        return deliveryService.pageQueryListLog(dto);
    }

    /**
     * 后台运单详情
     */
    @SaCheckPermission("delivery:view")
    @GetMapping("/detail")
    public AjaxResult detail(@RequestParam Integer id) {
        return deliveryService.detail(id);
    }

    /**
     * 查看运送订单详情（别名）
     */
    @SaCheckPermission("delivery:view")
    @GetMapping("/viewDeliveryOrder")
    public AjaxResult viewDeliveryOrder(@RequestParam Integer deliveryId) {
        return deliveryService.detail(deliveryId);
    }

    /**
     * 测试司机信息查询
     */
    @GetMapping("/testDriverQuery/{deliveryId}")
    public AjaxResult testDriverQuery(@PathVariable("deliveryId") Integer deliveryId) {
        try {
            AjaxResult result = deliveryService.detail(deliveryId);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("测试失败: " + e.getMessage());
        }
    }

    /**
     * 调试用户信息接口
     */
    @GetMapping("/debugUserInfo")
    public AjaxResult debugUserInfo() {
        try {
            Map<String, Object> debugInfo = new HashMap<>();
            
            // 获取当前用户信息
            Integer userId = SecurityUtil.getCurrentUserId();
            String userName = SecurityUtil.getUserName();
            String userMobile = SecurityUtil.getUserMobile();
            Integer roleId = SecurityUtil.getRoleId();
            boolean isSuperAdmin = SecurityUtil.isSuperAdmin();
            
            debugInfo.put("userId", userId);
            debugInfo.put("userName", userName);
            debugInfo.put("userMobile", userMobile);
            debugInfo.put("roleId", roleId);
            debugInfo.put("isSuperAdmin", isSuperAdmin);
            debugInfo.put("superAdminRoleId", RoleConstants.SUPER_ADMIN_ROLE_ID);
            
            
            return AjaxResult.success("调试信息获取成功", debugInfo);
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("调试失败: " + e.getMessage());
        }
    }

    /**
     * 分配设备（支持智能耳标和智能项圈）
     * @param dto
     * @return
     */
    @SaCheckPermission("delivery:assign")
    @PostMapping(value = "/arrangeJbq")
    public AjaxResult arrangeJbq(@RequestBody DeviceAssignDto dto) {
        try {
            if (dto.getDeviceIds() == null || dto.getDeviceIds().isEmpty()) {
                return AjaxResult.error("请选择要分配的设备");
            }
            
            // 按设备类型分组
            Map<Integer, List<DeviceAssignDto.DeviceInfo>> deviceGroups = dto.getDeviceIds().stream()
                .collect(Collectors.groupingBy(DeviceAssignDto.DeviceInfo::getDeviceTypeId));
            
            // 处理每种设备类型
            for (Map.Entry<Integer, List<DeviceAssignDto.DeviceInfo>> entry : deviceGroups.entrySet()) {
                Integer deviceType = entry.getKey();
                List<DeviceAssignDto.DeviceInfo> devices = entry.getValue();
                
                // 先删除该运单的现有设备分配（按设备类型）
                deliveryDeviceService.lambdaUpdate()
                    .eq(DeliveryDevice::getDeliveryId, dto.getDeliveryId())
                    .eq(DeliveryDevice::getDeviceType, deviceType)
                    .remove();
                
                // 添加新的设备分配
                for (DeviceAssignDto.DeviceInfo deviceInfo : devices) {
                    DeliveryDevice deliveryDevice = new DeliveryDevice();
                    deliveryDevice.setDeliveryId(dto.getDeliveryId());
                    deliveryDevice.setDeviceId(deviceInfo.getDeviceId());
                    deliveryDevice.setDeviceType(deviceType);
                    deliveryDeviceService.save(deliveryDevice);
                    
                    // 更新设备的运单号和车牌号
                    updateDeviceDeliveryInfo(deviceInfo.getDeviceId(), deviceType, dto.getDeliveryId(), dto.getLicensePlate());
                }
            }
            
            return AjaxResult.success("设备分配成功！");
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("设备分配失败：" + e.getMessage());
        }
    }
    
    /**
     * 更新设备的运单号和车牌号
     */
    private void updateDeviceDeliveryInfo(String deviceId, Integer deviceType, Integer deliveryId, String licensePlate) {
        try {
            // 获取运单号
            Delivery delivery = deliveryService.getById(deliveryId);
            String deliveryNumber = delivery != null ? delivery.getDeliveryNumber() : "";
            
            if (deviceType == 2) {
                // 更新智能耳标
                LambdaUpdateWrapper<JbqClient> jbqUpdateWrapper = new LambdaUpdateWrapper<>();
                jbqUpdateWrapper.eq(JbqClient::getDeviceId, deviceId);
                jbqUpdateWrapper.set(JbqClient::getDeliveryNumber, deliveryNumber);
                jbqUpdateWrapper.set(JbqClient::getLicensePlate, licensePlate);
                jbqClientService.update(jbqUpdateWrapper);
            } else if (deviceType == 3) {
                // 更新智能项圈 - 兼容deviceId和sn两种字段
                LambdaUpdateWrapper<XqClient> xqUpdateWrapper = new LambdaUpdateWrapper<>();
                xqUpdateWrapper.and(w -> w.eq(XqClient::getDeviceId, deviceId)
                                          .or()
                                          .eq(XqClient::getSn, Long.parseLong(deviceId)));
                xqUpdateWrapper.set(XqClient::getDeliveryId, deliveryId);
                xqUpdateWrapper.set(XqClient::getDeliveryNumber, deliveryNumber);
                xqUpdateWrapper.set(XqClient::getLicensePlate, licensePlate);
                xqClientService.update(xqUpdateWrapper);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 修改运送清单状态
     * 状态值：1-准备中，2-运输中，3-已结束
     */
    @SaCheckPermission("delivery:edit")
    @PostMapping("/updateStatus")
    public AjaxResult updateStatus(@RequestBody Map<String, Object> params) {
        try {
            Integer id = (Integer) params.get("id");
            Integer status = (Integer) params.get("status");
            
            
            if (id == null || status == null) {
                return AjaxResult.error("运单ID和状态不能为空");
            }
            
            if (status < 1 || status > 3) {
                return AjaxResult.error("状态值无效，只能为1（准备中）、2（运输中）、3（已结束）");
            }
            
            // 查询运单是否存在
            Delivery existDelivery = deliveryService.getById(id);
            if (existDelivery == null) {
                return AjaxResult.error("运单不存在");
            }

            if (status == 2) {
                if (StringUtils.isBlank(existDelivery.getLicensePlate())) {
                    return AjaxResult.error("车牌号为空，无法开启运输状态");
                }
                // 去除车牌号中的空格，确保格式一致
                String licensePlate = existDelivery.getLicensePlate().trim();
                String entityName = StringUtils.defaultIfBlank(existDelivery.getYingyanEntityName(), licensePlate);
                // 如果终端名称与车牌号不一致，使用车牌号（去除空格）
                if (!licensePlate.equals(entityName)) {
                    entityName = licensePlate;
                }
                boolean ensureResult = baiduYingyanService.ensureEntity(entityName);

                Delivery syncInfo = new Delivery();
                syncInfo.setId(id);
                syncInfo.setYingyanEntityName(entityName);
                if (existDelivery.getYingyanLastSyncTime() == null) {
                    Date syncStart = existDelivery.getEstimatedDeliveryTime();
                    if (syncStart == null) {
                        syncStart = existDelivery.getEstimatedDepartureTime();
                    }
                    if (syncStart == null) {
                        syncStart = existDelivery.getCreateTime();
                    }
                    syncInfo.setYingyanLastSyncTime(syncStart);
                }
                deliveryService.updateById(syncInfo);

                if (!ensureResult) {
                    logger.warn("运单 {} 创建百度鹰眼终端失败，将在后台重试", existDelivery.getDeliveryNumber());
                }
            } else if (status == 3) {
                Delivery arrivalUpdate = new Delivery();
                arrivalUpdate.setId(id);
                arrivalUpdate.setArrivalTime(new Date());
                deliveryService.updateById(arrivalUpdate);
            }

            Delivery delivery = new Delivery();
            delivery.setId(id);
            delivery.setStatus(status);
            
            boolean success = deliveryService.updateById(delivery);
            
            if (success) {
                String statusText = status == 1 ? "准备中" : (status == 2 ? "运输中" : "已结束");
                return AjaxResult.success("状态更新成功");
            } else {
                return AjaxResult.error("状态更新失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("状态更新失败：" + e.getMessage());
        }
    }

    /**
     * 查询运送清单百度鹰眼轨迹/停留点
     */
    @SaCheckPermission("delivery:view")
    @PostMapping("/yingyan/track")
    public AjaxResult getYingyanTrack(@Validated @RequestBody DeliveryTrackQueryDto dto) {
        return deliveryService.queryYingyanTrack(dto.getDeliveryId());
    }

    /**
     * 删除装车订单（物理删除）
     * 删除订单时同时清空关联设备的delivery_id和weight
     */
    @SaCheckPermission("delivery:delete")
    @GetMapping("/deleteDelivery")
    public AjaxResult deleteDelivery(@RequestParam Integer id) {
        try {
            if (id == null) {
                return AjaxResult.error("订单ID不能为空");
            }
            
            
            // 查询订单是否存在
            Delivery delivery = deliveryService.getById(id);
            if (delivery == null) {
                return AjaxResult.error("订单不存在");
            }
            
            // 权限检查：只有创建者或超级管理员可以删除
            Integer userId = SecurityUtil.getCurrentUserId();
            if (!SecurityUtil.isSuperAdmin() && !userId.equals(delivery.getCreatedBy())) {
                return AjaxResult.error("无权限删除此订单");
            }
            
            // 1. 先清空关联设备的delivery_id和weight
            com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<com.aiotagro.cattletrade.business.entity.IotDeviceData> queryWrapper = 
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>();
            queryWrapper.eq("delivery_id", id);
            List<com.aiotagro.cattletrade.business.entity.IotDeviceData> devices = iotDeviceDataMapper.selectList(queryWrapper);
            
            int updatedCount = 0;
            for (com.aiotagro.cattletrade.business.entity.IotDeviceData device : devices) {
                device.setDeliveryId(null);
                device.setWeight(null);
                device.setCarNumber(null);
                iotDeviceDataMapper.updateById(device);
                updatedCount++;
            }
            
            
            // 2. 删除订单记录
            boolean deleted = deliveryService.removeById(id);
            
            if (deleted) {
                return AjaxResult.success("订单删除成功，已清空 " + updatedCount + " 个设备的绑定信息");
            } else {
                return AjaxResult.error("订单删除失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("删除订单失败：" + e.getMessage());
        }
    }
    
    /**
     * 逻辑删除运送清单
     * 逻辑删除时同时清空关联设备的delivery_id和car_number
     */
    @SaCheckPermission("delivery:delete")
    @PostMapping("/deleteLogic")
    public AjaxResult deleteLogic(@RequestParam Integer id) {
        try {
            if (id == null) {
                return AjaxResult.error("运单ID不能为空");
            }
            
            
            // 查询订单是否存在
            Delivery delivery = deliveryService.getById(id);
            if (delivery == null) {
                return AjaxResult.error("运单不存在");
            }
            
            // 权限检查：只有创建者或超级管理员可以删除
            Integer userId = SecurityUtil.getCurrentUserId();
            if (!SecurityUtil.isSuperAdmin() && !userId.equals(delivery.getCreatedBy())) {
                return AjaxResult.error("无权限删除此运单");
            }
            
            // 1. 先清空关联设备的delivery_id和car_number
            com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<com.aiotagro.cattletrade.business.entity.IotDeviceData> queryWrapper = 
                new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>();
            queryWrapper.eq("delivery_id", id);
            List<com.aiotagro.cattletrade.business.entity.IotDeviceData> devices = iotDeviceDataMapper.selectList(queryWrapper);
            
            int updatedCount = 0;
            for (com.aiotagro.cattletrade.business.entity.IotDeviceData device : devices) {
                // 使用LambdaUpdateWrapper确保null值也能被更新
                com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<com.aiotagro.cattletrade.business.entity.IotDeviceData> updateWrapper = 
                    new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<>();
                updateWrapper.eq(com.aiotagro.cattletrade.business.entity.IotDeviceData::getDeviceId, device.getDeviceId())
                            .set(com.aiotagro.cattletrade.business.entity.IotDeviceData::getDeliveryId, null)
                            .set(com.aiotagro.cattletrade.business.entity.IotDeviceData::getCarNumber, null)
                            .set(com.aiotagro.cattletrade.business.entity.IotDeviceData::getUpdateTime, new Date());
                
                int result = iotDeviceDataMapper.update(null, updateWrapper);
                if (result > 0) {
                    updatedCount++;
                    logger.debug("清空设备绑定信息: deviceId={}, delivery_id=null, car_number=null", device.getDeviceId());
                }
            }
            
            logger.info("逻辑删除运送清单，已清空 {} 个设备的绑定信息，运单ID: {}", updatedCount, id);
            
            // 2. 使用 MyBatis-Plus 的逻辑删除功能
            boolean deleted = deliveryService.removeById(id);
            
            if (deleted) {
                return AjaxResult.success("运单删除成功，已清空 " + updatedCount + " 个设备的绑定信息");
            } else {
                return AjaxResult.error("运单删除失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("删除运单失败：" + e.getMessage());
        }
    }
    
    /**
     * 打包下载运送清单文件（图片、视频、信息）
     * 包含所有相关的照片、视频和详细信息
     */
    @SaCheckPermission("delivery:view")
    @GetMapping("/downloadPackage")
    public void downloadPackage(@RequestParam Integer id, HttpServletResponse response) {
        
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ZipOutputStream zipOut = null;
        COSClient cosClient = null;
        
        try {
            if (id == null) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.setContentType("text/plain;charset=UTF-8");
                response.getWriter().write("运单ID不能为空");
                return;
            }
            
            // 查询运单详情
            Delivery delivery = deliveryService.getById(id);
            if (delivery == null) {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.setContentType("text/plain;charset=UTF-8");
                response.getWriter().write("运单不存在");
                return;
            }
            
            
            zipOut = new ZipOutputStream(byteArrayOutputStream);
            zipOut.setLevel(9); // 设置压缩级别
            
            // 1. 创建信息文本文件
            addDeliveryInfoToZip(zipOut, delivery);
            
            // 创建COS客户端（如果URL是COS URL，将在addFileToZip中创建）
            // 预先创建COS客户端，避免重复创建
            if (delivery.getQuarantineTickeyUrl() != null && 
                delivery.getQuarantineTickeyUrl().contains(TencentCloudConstants.TENCENT_CLOUD_BUCKET + ".cos")) {
                com.qcloud.cos.auth.BasicCOSCredentials cred = new com.qcloud.cos.auth.BasicCOSCredentials(
                    TencentCloudConstants.TENCENT_CLOUD_SECRETID, 
                    TencentCloudConstants.TENCENT_CLOUD_SECRETKEY
                );
                com.qcloud.cos.region.Region region = new com.qcloud.cos.region.Region(TencentCloudConstants.TENCENT_CLOUD_REGION);
                com.qcloud.cos.ClientConfig clientConfig = new com.qcloud.cos.ClientConfig(region);
                clientConfig.setHttpProtocol(com.qcloud.cos.http.HttpProtocol.https);
                cosClient = new COSClient(cred, clientConfig);
                logger.debug("创建COS客户端用于下载文件");
            }
            
            // 2. 下载并添加所有照片
            int photoCount = 0;
            logger.info("开始添加照片到ZIP，运单ID: {}", id);
            photoCount += addFileToZip(zipOut, delivery.getQuarantineTickeyUrl(), "照片/检疫票.jpg", "检疫票", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getPoundListImg(), "照片/纸质磅单.jpg", "纸质磅单", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getEmptyVehicleFrontPhoto(), "照片/空车过磅车头照片.jpg", "空车过磅车头照片", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getLoadedVehicleFrontPhoto(), "照片/装车过磅车头照片.jpg", "装车过磅车头照片", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getLoadedVehicleWeightPhoto(), "照片/装车过磅磅单.jpg", "装车过磅磅单", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getCarFrontPhoto(), "照片/车头照片.jpg", "车头照片", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getCarBehindPhoto(), "照片/车尾照片.jpg", "车尾照片", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getDriverIdCardPhoto(), "照片/司机身份证照片.jpg", "司机身份证照片", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getDestinationPoundListImg(), "照片/到地磅单.jpg", "到地磅单", cosClient);
            photoCount += addFileToZip(zipOut, delivery.getDestinationVehicleFrontPhoto(), "照片/到地车辆过重磅车头照片.jpg", "到地车辆过重磅车头照片", cosClient);
            logger.info("照片添加完成，成功添加 {} 张照片", photoCount);
            
            // 3. 下载并添加所有视频
            int videoCount = 0;
            logger.info("开始添加视频到ZIP，运单ID: {}", id);
            videoCount += addFileToZip(zipOut, delivery.getEmptyWeightVideo(), "视频/空车过磅视频.mp4", "空车过磅视频", cosClient);
            videoCount += addFileToZip(zipOut, delivery.getEntruckWeightVideo(), "视频/装车过磅视频.mp4", "装车过磅视频", cosClient);
            videoCount += addFileToZip(zipOut, delivery.getEntruckVideo(), "视频/装车视频.mp4", "装车视频", cosClient);
            videoCount += addFileToZip(zipOut, delivery.getControlSlotVideo(), "视频/消毒槽视频.mp4", "消毒槽视频", cosClient);
            videoCount += addFileToZip(zipOut, delivery.getCattleLoadingCircleVideo(), "视频/牛只装车环视视频.mp4", "牛只装车环视视频", cosClient);
            videoCount += addFileToZip(zipOut, delivery.getUnloadCattleVideo(), "视频/卸牛视频.mp4", "卸牛视频", cosClient);
            videoCount += addFileToZip(zipOut, delivery.getDestinationWeightVideo(), "视频/到地过磅视频.mp4", "到地过磅视频", cosClient);
            logger.info("视频添加完成，成功添加 {} 个视频", videoCount);
            
            
            zipOut.finish();
            zipOut.close();
            
            // 设置响应头
            byte[] zipBytes = byteArrayOutputStream.toByteArray();
            String fileName = "运送清单_" + delivery.getDeliveryNumber() + "_" + System.currentTimeMillis() + ".zip";
            String encodedFileName = URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName);
            response.setContentLength(zipBytes.length);
            
            OutputStream out = response.getOutputStream();
            out.write(zipBytes);
            out.flush();
            out.close();
            
            
        } catch (Exception e) {
            logger.error("打包文件失败，运单ID: {}", id, e);
            try {
                // 确保响应头已设置，避免被错误处理为登录过期
                if (!response.isCommitted()) {
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    response.setContentType("text/plain;charset=UTF-8");
                    response.getWriter().write("打包文件失败：" + e.getMessage());
                }
            } catch (IOException ioException) {
                logger.error("写入错误响应失败", ioException);
            }
        } finally {
            try {
                if (zipOut != null) {
                    zipOut.close();
                }
                byteArrayOutputStream.close();
                // 关闭COS客户端
                if (cosClient != null) {
                    cosClient.shutdown();
                }
            } catch (IOException e) {
                logger.warn("关闭资源失败", e);
            }
        }
    }
    
    /**
     * 添加运送清单信息到ZIP文件
     */
    private void addDeliveryInfoToZip(ZipOutputStream zipOut, Delivery delivery) throws IOException {
        StringBuilder info = new StringBuilder();
        info.append("====== 运送清单详细信息 ======\n\n");
        info.append("【基础信息】\n");
        info.append("运单号: ").append(delivery.getDeliveryNumber()).append("\n");
        info.append("车牌号: ").append(delivery.getLicensePlate()).append("\n");
        info.append("司机姓名: ").append(delivery.getDriverName()).append("\n");
        info.append("司机手机: ").append(delivery.getDriverMobile()).append("\n");
        info.append("起始地: ").append(delivery.getStartLocation()).append("\n");
        info.append("目的地: ").append(delivery.getEndLocation()).append("\n");
        info.append("预计送达时间: ").append(delivery.getEstimatedDeliveryTime()).append("\n");
        info.append("创建时间: ").append(delivery.getCreateTime()).append("\n\n");
        
        info.append("【重量信息】\n");
        info.append("空车过磅重量: ").append(delivery.getEmptyWeight()).append(" kg\n");
        info.append("装车过磅重量: ").append(delivery.getEntruckWeight()).append(" kg\n");
        info.append("落地过磅重量: ").append(delivery.getLandingEntruckWeight()).append(" kg\n\n");
        
        info.append("【状态信息】\n");
        String statusText = delivery.getStatus() == 1 ? "准备中" : (delivery.getStatus() == 2 ? "运输中" : "已结束");
        info.append("运输状态: ").append(statusText).append("\n\n");
        
        info.append("====== 文件生成时间: ").append(LocalDateTime.now()).append(" ======\n");
        
        ZipEntry entry = new ZipEntry("运送清单信息.txt");
        zipOut.putNextEntry(entry);
        zipOut.write(info.toString().getBytes(StandardCharsets.UTF_8));
        zipOut.closeEntry();
        
    }
    
    /**
     * 从URL下载文件并添加到ZIP
     * 优先使用腾讯云COS SDK下载，如果URL不是COS URL则使用HttpURLConnection
     * @param zipOut ZIP输出流
     * @param fileUrl 文件URL
     * @param fileName ZIP中的文件名
     * @param fileDescription 文件描述（用于日志）
     * @param cosClient COS客户端（如果已创建，可复用；如果为null，会在需要时创建）
     * @return 成功添加返回1，失败或URL为空返回0
     */
    private int addFileToZip(ZipOutputStream zipOut, String fileUrl, String fileName, String fileDescription, COSClient cosClient) {
        if (fileUrl == null || fileUrl.trim().isEmpty()) {
            logger.debug("跳过添加文件: {} (URL为空)", fileDescription);
            return 0;
        }
        
        InputStream inputStream = null;
        try {
            logger.debug("开始下载文件: {}，URL: {}", fileDescription, fileUrl);
            
            // 检查是否是腾讯云COS的URL
            if (fileUrl.contains(TencentCloudConstants.TENCENT_CLOUD_BUCKET + ".cos")) {
                // 使用COS SDK下载文件
                try {
                    // 从URL中提取COS对象键（key）
                    // URL格式: https://smart-1251449951.cos.ap-guangzhou.myqcloud.com/iotPlateform/2025/11/04/文件名.jpg
                    String cosKey = extractCosKeyFromUrl(fileUrl);
                    if (cosKey == null) {
                        logger.warn("无法从URL中提取COS键: {}，URL: {}", fileDescription, fileUrl);
                        return 0;
                    }
                    
                    // 使用COS客户端下载文件
                    // 如果传入的cosClient为null，则创建新的客户端
                    COSClient clientToUse = cosClient;
                    if (clientToUse == null) {
                        com.qcloud.cos.auth.BasicCOSCredentials cred = new com.qcloud.cos.auth.BasicCOSCredentials(
                            TencentCloudConstants.TENCENT_CLOUD_SECRETID, 
                            TencentCloudConstants.TENCENT_CLOUD_SECRETKEY
                        );
                        com.qcloud.cos.region.Region region = new com.qcloud.cos.region.Region(TencentCloudConstants.TENCENT_CLOUD_REGION);
                        com.qcloud.cos.ClientConfig clientConfig = new com.qcloud.cos.ClientConfig(region);
                        clientConfig.setHttpProtocol(com.qcloud.cos.http.HttpProtocol.https);
                        clientToUse = new COSClient(cred, clientConfig);
                    }
                    
                    GetObjectRequest getObjectRequest = new GetObjectRequest(
                        TencentCloudConstants.TENCENT_CLOUD_BUCKET, 
                        cosKey
                    );
                    com.qcloud.cos.model.COSObject cosObject = clientToUse.getObject(getObjectRequest);
                    inputStream = cosObject.getObjectContent();
                    
                    logger.debug("使用COS SDK下载文件: {}，COS键: {}", fileDescription, cosKey);
                } catch (Exception e) {
                    logger.warn("使用COS SDK下载文件失败: {}，URL: {}，错误: {}，尝试使用HttpURLConnection", 
                        fileDescription, fileUrl, e.getMessage());
                    // 如果COS SDK失败，回退到HttpURLConnection
                    inputStream = downloadViaHttp(fileUrl);
                }
            } else {
                // 非COS URL，使用HttpURLConnection
                inputStream = downloadViaHttp(fileUrl);
            }
            
            if (inputStream == null) {
                logger.warn("无法获取文件输入流: {}，URL: {}", fileDescription, fileUrl);
                return 0;
            }
            
            ZipEntry entry = new ZipEntry(fileName);
            zipOut.putNextEntry(entry);
            
            byte[] buffer = new byte[8192];
            int bytesRead;
            long totalBytes = 0;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                zipOut.write(buffer, 0, bytesRead);
                totalBytes += bytesRead;
            }
            
            zipOut.closeEntry();
            logger.debug("成功添加文件: {}，大小: {} 字节", fileDescription, totalBytes);
            return 1;
            
        } catch (Exception e) {
            logger.error("添加文件到ZIP时发生错误: {}，URL: {}", fileDescription, fileUrl, e);
            return 0;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    logger.warn("关闭输入流失败: {}", e.getMessage());
                }
            }
        }
    }
    
    /**
     * 从COS URL中提取对象键（key）
     * @param fileUrl COS文件URL
     * @return COS对象键，如果无法提取则返回null
     */
    private String extractCosKeyFromUrl(String fileUrl) {
        try {
            // URL格式: https://smart-1251449951.cos.ap-guangzhou.myqcloud.com/iotPlateform/2025/11/04/文件名.jpg
            URL url = new URL(fileUrl);
            String path = url.getPath();
            if (path != null && path.startsWith("/")) {
                return path.substring(1); // 移除开头的 "/"
            }
            return path;
        } catch (Exception e) {
            logger.warn("提取COS键失败，URL: {}，错误: {}", fileUrl, e.getMessage());
            return null;
        }
    }
    
    /**
     * 使用HttpURLConnection下载文件
     * @param fileUrl 文件URL
     * @return 输入流，如果失败返回null
     */
    private InputStream downloadViaHttp(String fileUrl) {
        try {
            // 对URL进行编码处理（特别是中文字符）
            URL url = new URL(fileUrl);
            java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(10000); // 10秒连接超时
            connection.setReadTimeout(30000); // 30秒读取超时
            connection.setRequestMethod("GET");
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");
            
            int responseCode = connection.getResponseCode();
            if (responseCode != java.net.HttpURLConnection.HTTP_OK) {
                logger.warn("HTTP下载失败，响应码: {}，URL: {}", responseCode, fileUrl);
                return null;
            }
            
            return connection.getInputStream();
        } catch (Exception e) {
            logger.warn("HttpURLConnection下载失败，URL: {}，错误: {}", fileUrl, e.getMessage());
            return null;
        }
        }

    /**
     * 下载验收单（生成HTML格式的牛只发车验收单）
     * 
     * @param id 运单ID
     * @param response HTTP响应
     */
    @SaCheckPermission("delivery:export")
    @GetMapping("/downloadAcceptanceForm")
    public void downloadAcceptanceForm(@RequestParam Integer id, HttpServletResponse response) {
        logger.info("开始生成验收单，运单ID: {}", id);
        
        try {
            if (id == null) {
                logger.warn("运单ID不能为空");
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.setContentType("text/plain;charset=UTF-8");
                response.getWriter().write("运单ID不能为空");
                return;
            }
            
            // 查询运单详情
            Delivery delivery = deliveryService.getById(id);
            if (delivery == null) {
                logger.warn("运单不存在，ID: {}", id);
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                response.setContentType("text/plain;charset=UTF-8");
                response.getWriter().write("运单不存在");
                return;
            }
            
            logger.info("查询到运单信息，运单号: {}, 车牌号: {}", delivery.getDeliveryNumber(), delivery.getLicensePlate());
            
            // 查询供应商名称（如果supplierName为空）
            if (delivery.getSupplierName() == null || delivery.getSupplierName().isEmpty()) {
                if (delivery.getSupplierId() != null && !delivery.getSupplierId().isEmpty()) {
                    try {
                        String[] supplierIds = delivery.getSupplierId().split(",");
                        List<String> supplierNames = new ArrayList<>();
                        for (String supplierId : supplierIds) {
                            if (StringUtils.isNotEmpty(supplierId.trim())) {
                                try {
                                    Integer sid = Integer.parseInt(supplierId.trim());
                                    Map<String, Object> supplierInfo = memberMapper.selectMemberUserById(sid);
                                    if (supplierInfo != null) {
                                        String username = (String) supplierInfo.get("username");
                                        if (StringUtils.isNotEmpty(username)) {
                                            supplierNames.add(username);
                                        }
                                    }
                                } catch (NumberFormatException e) {
                                    logger.warn("供应商ID格式错误: {}", supplierId);
                                }
                            }
                        }
                        if (!supplierNames.isEmpty()) {
                            delivery.setSupplierName(String.join(",", supplierNames));
                        }
                    } catch (Exception e) {
                        logger.error("查询供应商信息失败，运单ID: {}", id, e);
                    }
                }
            }
            
            // 查询采购商名称（如果buyerName为空）
            if (delivery.getBuyerName() == null || delivery.getBuyerName().isEmpty()) {
                if (delivery.getBuyerId() != null) {
                    try {
                        Map<String, Object> buyerInfo = memberMapper.selectMemberUserById(delivery.getBuyerId());
                        if (buyerInfo != null) {
                            String username = (String) buyerInfo.get("username");
                            String mobile = (String) buyerInfo.get("mobile");
                            if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(mobile)) {
                                delivery.setBuyerName(username + "/" + mobile);
                            } else if (StringUtils.isNotEmpty(username)) {
                                delivery.setBuyerName(username);
                            } else if (StringUtils.isNotEmpty(mobile)) {
                                delivery.setBuyerName(mobile);
                            }
                        }
                    } catch (Exception e) {
                        logger.error("查询采购商信息失败，运单ID: {}", id, e);
                    }
                }
            }
            
            // 准备数据 - 供货单位（卖方字段，只取姓名，不要手机号）
            String supplierName = delivery.getSupplierName();
            if (supplierName != null && !supplierName.isEmpty()) {
                // 如果包含"/"，取"/"前面的部分（姓名部分）
                if (supplierName.contains("/")) {
                    supplierName = supplierName.split("/")[0].trim();
                }
                // 如果包含逗号分隔（多个供应商），取第一个并处理"/"
                if (supplierName.contains(",")) {
                    String[] parts = supplierName.split(",");
                    supplierName = parts[0].trim();
                    if (supplierName.contains("/")) {
                        supplierName = supplierName.split("/")[0].trim();
                    }
                }
            } else {
                // 如果supplierName为空，使用supplierMobile作为备选（但通常不应该这样做，因为这是姓名字段）
                supplierName = "";
            }
            
            // 准备数据 - 收货单位（买方字段，只取姓名，不要手机号）
            String buyerName = delivery.getBuyerName();
            if (buyerName != null && !buyerName.isEmpty()) {
                // 如果包含"/"，取"/"前面的部分（姓名部分）
                if (buyerName.contains("/")) {
                    buyerName = buyerName.split("/")[0].trim();
                }
                // 如果包含逗号分隔（多个采购商），取第一个并处理"/"
                if (buyerName.contains(",")) {
                    String[] parts = buyerName.split(",");
                    buyerName = parts[0].trim();
                    if (buyerName.contains("/")) {
                        buyerName = buyerName.split("/")[0].trim();
                    }
                }
            } else {
                // 如果buyerName为空，使用buyerMobile作为备选（但通常不应该这样做，因为这是姓名字段）
                buyerName = "";
            }
            
            logger.info("提取的供货单位: {}, 收货单位: {}", supplierName, buyerName);
            
            String startLocation = delivery.getStartLocation() != null ? delivery.getStartLocation() : "";
            String endLocation = delivery.getEndLocation() != null ? delivery.getEndLocation() : "";
            String licensePlate = delivery.getLicensePlate() != null ? delivery.getLicensePlate() : "";
            
            // 格式化发车时间
            String departureTime = "";
            if (delivery.getEstimatedDepartureTime() != null) {
                try {
                    // Date 转 LocalDateTime
                    java.time.LocalDateTime localDateTime = delivery.getEstimatedDepartureTime().toInstant()
                        .atZone(java.time.ZoneId.systemDefault())
                        .toLocalDateTime();
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd");
                    departureTime = localDateTime.format(formatter);
                } catch (Exception e) {
                    logger.warn("格式化发车时间失败，使用默认格式，运单ID: {}", id, e);
                    // 如果格式化失败，使用默认格式
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
                    departureTime = sdf.format(delivery.getEstimatedDepartureTime());
                }
            }
            
            // 处理司机姓名和联系方式
            String driverName = delivery.getDriverName() != null ? delivery.getDriverName() : "";
            String driverMobile = delivery.getDriverMobile() != null ? delivery.getDriverMobile() : "";
            String driverInfo = "";
            if (!driverName.isEmpty() && driverName.contains("/")) {
                // 如果司机姓名包含"/"，取前面部分作为姓名
                String[] parts = driverName.split("/");
                driverInfo = parts[0];
                if (parts.length > 1) {
                    driverInfo += " " + parts[1];
                } else if (!driverMobile.isEmpty()) {
                    driverInfo += " " + driverMobile;
                }
            } else {
                driverInfo = driverName;
                if (!driverMobile.isEmpty()) {
                    driverInfo += " " + driverMobile;
                }
            }
            
            // 获取检疫证号（从检疫票URL中提取，如果有的话）
            String quarantineCertNo = "";
            if (delivery.getQuarantineTickeyUrl() != null && !delivery.getQuarantineTickeyUrl().isEmpty()) {
                // 可以根据实际情况提取检疫证号，这里暂时留空
                quarantineCertNo = "";
            }
            
            // 获取订单编号（优先使用deliveryNumber，如果没有则使用orderId）
            String orderNumber = delivery.getDeliveryNumber() != null ? delivery.getDeliveryNumber() : "";
            if (orderNumber.isEmpty() && delivery.getOrderId() != null) {
                orderNumber = "ORDER-" + delivery.getOrderId();
            }
            
            // 查询订单信息，获取结算方式描述、单价等信息
            String weightColumnTitle = "下车总重量(斤)"; // 默认值
            Integer settlementType = null; // 结算方式：1-上车重量，2-下车重量，3-按肉价结算
            java.math.BigDecimal unitPrice = null; // 单价(元/斤)
            
            if (delivery.getOrderId() != null) {
                try {
                    Order order = orderMapper.selectById(delivery.getOrderId());
                    if (order != null) {
                        // 获取结算方式
                        if (order.getSettlementType() != null) {
                            settlementType = order.getSettlementType();
                            if (settlementType == 1) {
                                // 上车重量 -> 上车总重量(斤)
                                weightColumnTitle = "上车总重量(斤)";
                                logger.info("订单结算方式为上车重量，使用重量字段标题: {}", weightColumnTitle);
                            } else if (settlementType == 2) {
                                // 下车重量 -> 下车总重量(斤)
                                weightColumnTitle = "下车总重量(斤)";
                                logger.info("订单结算方式为下车重量，使用重量字段标题: {}", weightColumnTitle);
                            } else if (settlementType == 3) {
                                // 按肉价结算 -> 保持默认"下车总重量(斤)"
                                weightColumnTitle = "下车总重量(斤)";
                                logger.info("订单结算方式为按肉价结算，使用默认重量字段标题: {}", weightColumnTitle);
                            }
                        }
                        
                        // 获取单价(元/斤)
                        if (order.getFirmPrice() != null) {
                            unitPrice = order.getFirmPrice();
                            logger.info("获取订单单价: firmPrice={}", unitPrice);
                        } else {
                            logger.warn("订单单价为空，订单ID: {}", delivery.getOrderId());
                        }
                    } else {
                        logger.warn("订单不存在，订单ID: {}, 使用默认值", delivery.getOrderId());
                    }
                } catch (Exception e) {
                    logger.error("查询订单信息失败，订单ID: {}", delivery.getOrderId(), e);
                }
            } else {
                logger.warn("运单没有关联订单，使用默认值");
            }
            
            // 计算总重量(斤)和总金额(元)
            Integer ratedQuantity = delivery.getRatedQuantity(); // 下车总数量(头)
            Double totalWeightJin = null; // 总重量(斤)
            Double totalAmount = null; // 总金额(元)
            
            // 解析重量字段（String类型，如"1000.00"）
            Double emptyWeightKg = null;
            Double entruckWeightKg = null;
            Double landingEntruckWeightKg = null;
            
            try {
                if (delivery.getEmptyWeight() != null && !delivery.getEmptyWeight().trim().isEmpty()) {
                    emptyWeightKg = Double.parseDouble(delivery.getEmptyWeight().trim());
                }
                if (delivery.getEntruckWeight() != null && !delivery.getEntruckWeight().trim().isEmpty()) {
                    entruckWeightKg = Double.parseDouble(delivery.getEntruckWeight().trim());
                }
                if (delivery.getLandingEntruckWeight() != null && !delivery.getLandingEntruckWeight().trim().isEmpty()) {
                    landingEntruckWeightKg = Double.parseDouble(delivery.getLandingEntruckWeight().trim());
                }
                
                // 根据结算方式计算总重量(斤)
                // 注意：重量字段存储的是公斤(kg)，需要转换为斤(斤 = kg * 2)
                if (settlementType != null && emptyWeightKg != null) {
                    if (settlementType == 1) {
                        // 上车重量：计算 (entruckWeight - emptyWeight) * 2
                        if (entruckWeightKg != null) {
                            totalWeightJin = (entruckWeightKg - emptyWeightKg) * 2;
                            logger.info("计算上车总重量: entruckWeight={}kg, emptyWeight={}kg, 总重量={}斤", 
                                entruckWeightKg, emptyWeightKg, totalWeightJin);
                        }
                    } else if (settlementType == 2) {
                        // 下车重量：计算 (landingEntruckWeight - emptyWeight) * 2
                        if (landingEntruckWeightKg != null) {
                            totalWeightJin = (landingEntruckWeightKg - emptyWeightKg) * 2;
                            logger.info("计算下车总重量: landingEntruckWeight={}kg, emptyWeight={}kg, 总重量={}斤", 
                                landingEntruckWeightKg, emptyWeightKg, totalWeightJin);
                        }
                    }
                }
                
                // 计算总金额(元) = 总重量(斤) * 单价(元/斤)
                if (totalWeightJin != null && unitPrice != null) {
                    totalAmount = totalWeightJin * unitPrice.doubleValue();
                    // 四舍五入保留2位小数
                    totalAmount = java.math.BigDecimal.valueOf(totalAmount)
                        .setScale(2, java.math.RoundingMode.HALF_UP)
                        .doubleValue();
                    logger.info("计算总金额: 总重量={}斤, 单价={}元/斤, 总金额={}元", 
                        totalWeightJin, unitPrice, totalAmount);
                }
            } catch (NumberFormatException e) {
                logger.error("解析重量字段失败: emptyWeight={}, entruckWeight={}, landingEntruckWeight={}", 
                    delivery.getEmptyWeight(), delivery.getEntruckWeight(), 
                    delivery.getLandingEntruckWeight(), e);
            }
            
            // 格式化数值为字符串（保留2位小数）
            String ratedQuantityStr = ratedQuantity != null ? String.valueOf(ratedQuantity) : "";
            String totalWeightStr = totalWeightJin != null ? 
                String.format("%.2f", totalWeightJin) : "";
            String unitPriceStr = unitPrice != null ? 
                unitPrice.setScale(2, java.math.RoundingMode.HALF_UP).toString() : "";
            String totalAmountStr = totalAmount != null ? 
                String.format("%.2f", totalAmount) : "";
            
            // 生成HTML内容
            String htmlContent = generateAcceptanceFormHtml(
                orderNumber, supplierName, buyerName, startLocation, 
                departureTime, endLocation, quarantineCertNo, 
                driverInfo, licensePlate, weightColumnTitle,
                ratedQuantityStr, totalWeightStr, unitPriceStr, totalAmountStr
            );
            
            // 设置响应头
            response.setContentType("text/html;charset=UTF-8");
            response.setHeader("Content-Disposition", 
                "inline; filename=\"" + URLEncoder.encode("牛只发车验收单_" + orderNumber + ".html", "UTF-8") + "\"");
            
            // 写入响应
            response.getWriter().write(htmlContent);
            response.getWriter().flush();
            
            logger.info("验收单生成成功，运单ID: {}, 运单号: {}", id, orderNumber);
            
        } catch (Exception e) {
            logger.error("生成验收单失败，运单ID: {}", id, e);
            try {
                if (!response.isCommitted()) {
                    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                    response.setContentType("text/plain;charset=UTF-8");
                    response.getWriter().write("生成验收单失败：" + e.getMessage());
                }
            } catch (IOException ioException) {
                logger.error("写入错误响应失败", ioException);
            }
        }
    }
    
    /**
     * 生成验收单HTML内容（严格按照图片格式要求）
     * @param weightColumnTitle 重量字段标题（根据结算方式动态设置：上车总重量(斤) 或 下车总重量(斤)）
     * @param ratedQuantity 下车总数量(头)
     * @param totalWeight 总重量(斤)
     * @param unitPrice 单价(元/斤)
     * @param totalAmount 总金额(元)
     */
    private String generateAcceptanceFormHtml(String orderNumber, String supplierName, 
                                             String buyerName, String startLocation,
                                             String departureTime, String endLocation,
                                             String quarantineCertNo, String driverInfo,
                                             String licensePlate, String weightColumnTitle,
                                             String ratedQuantity, String totalWeight, 
                                             String unitPrice, String totalAmount) {
        
        StringBuilder html = new StringBuilder();
        html.append("<!DOCTYPE html>\n");
        html.append("<html>\n");
        html.append("<head>\n");
        html.append("    <meta charset=\"UTF-8\">\n");
        html.append("    <title>牛只发车验收单</title>\n");
        html.append("    <style>\n");
        html.append("        @media print {\n");
        html.append("            body { margin: 0; }\n");
        html.append("            .no-print { display: none; }\n");
        html.append("        }\n");
        html.append("        body { \n");
        html.append("            font-family: \"Microsoft YaHei\", \"SimSun\", Arial, sans-serif; \n");
        html.append("            margin: 20px; \n");
        html.append("            line-height: 1.4;\n");
        html.append("        }\n");
        html.append("        .header { \n");
        html.append("            text-align: center; \n");
        html.append("            font-size: 20px; \n");
        html.append("            font-weight: bold; \n");
        html.append("            margin-bottom: 30px;\n");
        html.append("            border-bottom: 2px solid #000;\n");
        html.append("            padding-bottom: 10px;\n");
        html.append("        }\n");
        html.append("        .order-number { \n");
        html.append("            text-align: right; \n");
        html.append("            margin-bottom: 10px; \n");
        html.append("            font-size: 14px;\n");
        html.append("        }\n");
        html.append("        table { \n");
        html.append("            width: 100%; \n");
        html.append("            border-collapse: collapse; \n");
        html.append("            margin-bottom: 20px; \n");
        html.append("        }\n");
        html.append("        table td, table th { \n");
        html.append("            border: 1px solid #000; \n");
        html.append("            padding: 8px; \n");
        html.append("            text-align: left; \n");
        html.append("        }\n");
        html.append("        table th { \n");
        html.append("            background-color: #f0f0f0; \n");
        html.append("            font-weight: bold; \n");
        html.append("        }\n");
        html.append("        .print-button { \n");
        html.append("            padding: 10px 20px; \n");
        html.append("            background-color: #409EFF; \n");
        html.append("            color: white; \n");
        html.append("            border: none; \n");
        html.append("            border-radius: 4px; \n");
        html.append("            cursor: pointer; \n");
        html.append("            font-size: 14px; \n");
        html.append("        }\n");
        html.append("        .print-button:hover { \n");
        html.append("            background-color: #66b1ff; \n");
        html.append("        }\n");
        html.append("    </style>\n");
        html.append("</head>\n");
        html.append("<body>\n");
        
        // 附件2（左上角）
        html.append("    <div style=\"text-align: left; margin-bottom: 10px;\">附件2</div>\n");
        
        // 标题（居中，带下划线）
        html.append("    <div class=\"header\">牛只发车验收单</div>\n");
        
        // 订单编号（右上角）
        html.append("    <div class=\"order-number\">订单编号: ").append(orderNumber).append("</div>\n");
        
        // 基本信息表格（4行2列）
        html.append("    <table>\n");
        html.append("        <tr>\n");
        html.append("            <td style=\"width: 15%;\">供货单位</td>\n");
        html.append("            <td style=\"width: 35%;\">").append(supplierName).append("</td>\n");
        html.append("            <td style=\"width: 15%;\">收货单位</td>\n");
        html.append("            <td style=\"width: 35%;\">").append(buyerName).append("</td>\n");
        html.append("        </tr>\n");
        html.append("        <tr>\n");
        html.append("            <td>发车地点</td>\n");
        html.append("            <td>").append(startLocation).append("</td>\n");
        html.append("            <td>发车时间</td>\n");
        html.append("            <td>").append(departureTime).append("</td>\n");
        html.append("        </tr>\n");
        html.append("        <tr>\n");
        html.append("            <td>到达地点</td>\n");
        html.append("            <td>").append(endLocation).append("</td>\n");
        html.append("            <td>动物检疫合格证明编号</td>\n");
        html.append("            <td>").append(quarantineCertNo).append("</td>\n");
        html.append("        </tr>\n");
        html.append("        <tr>\n");
        html.append("            <td>司机姓名及联系方式</td>\n");
        html.append("            <td>").append(driverInfo).append("</td>\n");
        html.append("            <td>装车车牌号</td>\n");
        html.append("            <td>").append(licensePlate).append("</td>\n");
        html.append("        </tr>\n");
        html.append("    </table>\n");
        
        // 牛只明细表格（完整保留，但数据为空）
        html.append("    <table>\n");
        html.append("        <tr>\n");
        html.append("            <th style=\"width: 5%;\">序号</th>\n");
        html.append("            <th style=\"width: 15%;\">活牛品种</th>\n");
        html.append("            <th style=\"width: 15%;\">单只体重范围</th>\n");
        html.append("            <th style=\"width: 12%;\">下车总数量(头)</th>\n");
        html.append("            <th style=\"width: 12%;\">").append(weightColumnTitle).append("</th>\n");
        html.append("            <th style=\"width: 10%;\">单价(元/斤)</th>\n");
        html.append("            <th style=\"width: 15%;\">总金额(元)</th>\n");
        html.append("            <th style=\"width: 16%;\">备注</th>\n");
        html.append("        </tr>\n");
        html.append("        <tr>\n");
        html.append("            <td></td>\n");
        html.append("            <td></td>\n");
        html.append("            <td></td>\n");
        html.append("            <td>").append(ratedQuantity).append("</td>\n");
        html.append("            <td>").append(totalWeight).append("</td>\n");
        html.append("            <td>").append(unitPrice).append("</td>\n");
        html.append("            <td>").append(totalAmount).append("</td>\n");
        html.append("            <td></td>\n");
        html.append("        </tr>\n");
        html.append("    </table>\n");
        
        // 支付信息表格（完整保留，但数据为空）
        html.append("    <table>\n");
        html.append("        <tr>\n");
        html.append("            <td style=\"width: 15%;\">已支付货款时间</td>\n");
        html.append("            <td style=\"width: 35%;\"></td>\n");
        html.append("            <td style=\"width: 15%;\">已支付货款金额</td>\n");
        html.append("            <td style=\"width: 35%;\"></td>\n");
        html.append("        </tr>\n");
        html.append("        <tr>\n");
        html.append("            <td>应支付尾款时间</td>\n");
        html.append("            <td></td>\n");
        html.append("            <td>应支付尾款金额</td>\n");
        html.append("            <td></td>\n");
        html.append("        </tr>\n");
        html.append("    </table>\n");
        
        // 验收结论和签字盖章区域（完整保留，但数据为空）
        html.append("    <table>\n");
        html.append("        <tr>\n");
        html.append("            <td style=\"width: 15%;\">验收结论</td>\n");
        html.append("            <td style=\"width: 35%;\"></td>\n");
        html.append("            <td style=\"width: 15%;\">验收时间</td>\n");
        html.append("            <td style=\"width: 35%;\"></td>\n");
        html.append("        </tr>\n");
        html.append("        <tr>\n");
        html.append("            <td>供货单位指定验收人签字及联系方式</td>\n");
        html.append("            <td></td>\n");
        html.append("            <td>收货单位指定验收人签字及联系方式</td>\n");
        html.append("            <td></td>\n");
        html.append("        </tr>\n");
        html.append("        <tr>\n");
        html.append("            <td>供货单位盖章</td>\n");
        html.append("            <td></td>\n");
        html.append("            <td>收货单位盖章</td>\n");
        html.append("            <td></td>\n");
        html.append("        </tr>\n");
        html.append("    </table>\n");
        
        // 打印按钮（不打印时显示）
        html.append("    <div class=\"no-print\">\n");
        html.append("        <button class=\"print-button\" onclick=\"window.print()\">打印/保存为PDF</button>\n");
        html.append("        <p style=\"color: #666; font-size: 12px;\">\n");
        html.append("            提示：点击\"打印/保存为PDF\"按钮可以将此文档打印或保存为PDF格式。\n");
        html.append("            在打印对话框中，您也可以选择\"另存为PDF\"来保存文档。\n");
        html.append("        </p>\n");
        html.append("    </div>\n");
        html.append("</body>\n");
        html.append("</html>\n");
        
        return html.toString();
    }

}

