package com.ycwl.basic.service.printer.impl;

import cn.hutool.http.HttpUtil;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.constant.NumberConstant;
import com.ycwl.basic.constant.StorageConstant;
import com.ycwl.basic.enums.OrderStateEnum;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.image.watermark.ImageWatermarkFactory;
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
import com.ycwl.basic.image.watermark.enums.ImageWatermarkOperatorEnum;
import com.ycwl.basic.image.watermark.operator.IOperator;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.MemberMapper;
import com.ycwl.basic.mapper.OrderMapper;
import com.ycwl.basic.mapper.PrintTaskMapper;
import com.ycwl.basic.mapper.PrinterMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.mobile.face.FaceRecognizeResp;
import com.ycwl.basic.model.mobile.order.PriceObj;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
import com.ycwl.basic.model.pc.order.entity.OrderEntity;
import com.ycwl.basic.model.pc.order.entity.OrderItemEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.pricing.dto.PriceCalculationRequest;
import com.ycwl.basic.pricing.dto.PriceCalculationResult;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.service.IAutoCouponService;
import com.ycwl.basic.pricing.service.IPriceCalculationService;
import com.ycwl.basic.model.pc.printer.entity.MemberPrintEntity;
import com.ycwl.basic.model.pc.printer.entity.PrintTaskEntity;
import com.ycwl.basic.model.pc.printer.entity.PrinterEntity;
import com.ycwl.basic.model.pc.printer.resp.MemberPrintResp;
import com.ycwl.basic.model.pc.printer.resp.PrinterResp;
import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
import com.ycwl.basic.model.printer.req.FromSourceReq;
import com.ycwl.basic.model.printer.req.PrinterSyncReq;
import com.ycwl.basic.model.printer.req.WorkerAuthReqVo;
import com.ycwl.basic.model.printer.resp.PrintTaskResp;
import com.ycwl.basic.model.wx.WXPayOrderReqVO;
import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.OrderRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.mobile.WxPayService;
import com.ycwl.basic.service.pc.FaceService;
import com.ycwl.basic.service.printer.PrinterService;
import com.ycwl.basic.storage.StorageFactory;
import com.ycwl.basic.storage.adapters.IStorageAdapter;
import com.ycwl.basic.storage.enums.StorageAcl;
import com.ycwl.basic.utils.ApiResponse;
import com.ycwl.basic.utils.ImageUtils;
import com.ycwl.basic.utils.JacksonUtil;
import com.ycwl.basic.utils.SnowFlakeUtil;
import com.ycwl.basic.utils.WxMpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PrinterServiceImpl implements PrinterService {
    @Autowired
    private PrinterMapper printerMapper;
    @Autowired
    private SourceMapper sourceMapper;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    @Lazy
    private OrderBiz orderBiz;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private PrintTaskMapper printTaskMapper;
    @Autowired
    private IPriceCalculationService priceCalculationService;
    @Autowired
    private IAutoCouponService autoCouponService;
    @Autowired
    private ScenicRepository scenicRepository;
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private FaceSampleMapper faceSampleMapper;
    @Autowired
    private FaceMapper faceMapper;
    @Autowired
    private FaceRepository faceRepository;
    @Lazy
    @Autowired
    private FaceService faceService;
    @Autowired
    private DeviceRepository deviceRepository;

    // 用于优先打印的线程池,核心线程数根据实际情况调整
    private final ExecutorService preferPrintExecutor = Executors.newFixedThreadPool(
            Runtime.getRuntime().availableProcessors() * 2
    );

    @Override
    public List<PrinterResp> listByScenicId(Long scenicId) {
        return printerMapper.listByScenicId(scenicId);
    }

    @Override
    public ApiResponse<List<PrinterEntity>> list(PrinterEntity condition) {
        return ApiResponse.success(printerMapper.list(condition));
    }

    @Override
    public ApiResponse<PrinterEntity> get(Integer id) {
        return ApiResponse.success(printerMapper.getById(id));
    }

    @Override
    public ApiResponse<Integer> add(PrinterEntity entity) {
        ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(entity.getScenicId());
        Boolean printEnable = scenicConfig.getBoolean("print_enable");
        if (!Boolean.TRUE.equals(printEnable)) {
            return ApiResponse.fail("景区没有开启打印功能!");
        }
        return ApiResponse.success(printerMapper.add(entity));
    }

    @Override
    public ApiResponse<Integer> update(PrinterEntity payload) {
        PrinterEntity entity = printerMapper.getById(payload.getId());
        ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(entity.getScenicId());
        Boolean printEnable = scenicConfig.getBoolean("print_enable");
        if (!Boolean.TRUE.equals(printEnable)) {
            return ApiResponse.fail("景区没有开启打印功能!");
        }
        return ApiResponse.success(printerMapper.update(payload));
    }

    @Override
    public ApiResponse<Integer> delete(Integer id) {
        return ApiResponse.success(printerMapper.deleteById(id));
    }

    private PrinterEntity getPrinter(WorkerAuthReqVo req) {
        String accessKey = req.getAccessKey();
        if (accessKey == null) {
            return null;
        }
        PrinterEntity printer = printerMapper.findByAccessKey(accessKey);
        if (printer == null) {
            return null;
        }
        if (printer.getStatus() != 1) {
            return null;
        }
        return printer;
    }

    @Override
    public List<PrintTaskResp> sync(PrinterSyncReq req) {
        PrinterEntity printer = getPrinter(req);
        if (printer == null) {
            return Collections.emptyList();
        }
        List<String> printers = req.getPrinters();
        String printersStr = StringUtils.join(printers, "|");
        if (!Strings.CS.equals(printersStr, printer.getPrinters())) {
            printer.setPrinters(printersStr);
            printerMapper.update(printer);
        }
        syncTaskLock.lock();
        try {
            while (true) {
                PrintTaskResp task = printerMapper.findTaskByPrinterId(printer.getId());
                if (task == null) {
                    return Collections.emptyList();
                }
                int updatedRows = printerMapper.compareAndSetTaskStatus(
                        task.getId(),
                        TASK_STATUS_PENDING,
                        TASK_STATUS_PROCESSING
                );
                if (updatedRows == 1) {
                    task.setStatus(TASK_STATUS_PROCESSING);
                    return Collections.singletonList(task);
                }
            }
        } finally {
            syncTaskLock.unlock();
        }
    }

    @Override
    public void taskSuccess(Integer taskId, WorkerAuthReqVo req) {
        PrintTaskEntity task = printerMapper.getTaskById(taskId);
        if (task == null) {
            return;
        }
        PrinterEntity printer = getPrinter(req);
        if (printer == null) {
            return;
        }
        if (printer.getId().equals(task.getPrinterId())) {
            printerMapper.updateTaskStatus(taskId, 1);
        }
    }

    @Override
    public void taskFail(Integer taskId, WorkerAuthReqVo req) {
        PrintTaskEntity task = printerMapper.getTaskById(taskId);
        if (task == null) {
            return;
        }
        PrinterEntity printer = getPrinter(req);
        if (printer == null) {
            return;
        }
        if (printer.getId().equals(task.getPrinterId())) {
            printerMapper.updateTaskStatus(taskId, 2);
        }
    }

    @Override
    public List<MemberPrintResp> getUserPhotoList(Long userId, Long scenicId, Long faceId) {
        if (faceId == null) {
            List<MemberPrintResp> list = printerMapper.listRelation(userId, scenicId);
            return list.stream()
                    .filter(item -> Objects.isNull(item.getFaceId()))
                    .collect(Collectors.toList());
        }
        List<MemberPrintResp> list = printerMapper.listRelationByFaceId(userId, scenicId, faceId);
        return list;
    }

    @Override
    public List<MemberPrintResp> getUserPhotoListByOrderId(Long orderId) {
        return printerMapper.listRelationByOrderId(orderId);
    }

    @Override
    public boolean deleteUserPhoto(Long memberId, Long scenicId, Long relationId) {
        int record = printerMapper.deleteUserPhoto(memberId, scenicId, relationId);
        return record > 0;
    }

    @Override
    public Integer addUserPhoto(Long memberId, Long scenicId, String url, Long faceId, Long sourceId) {
        MemberPrintEntity entity = new MemberPrintEntity();
        entity.setMemberId(memberId);
        entity.setScenicId(scenicId);
        entity.setFaceId(faceId);
        entity.setSourceId(sourceId);
        entity.setOrigUrl(url);

        // 获取打印尺寸
        String cropUrl = url; // 默认使用原图
        try {
            // 从打印机表获取尺寸
            Integer printWidth = null;
            Integer printHeight = null;

            List<PrinterResp> printers = printerMapper.listByScenicId(scenicId);
            if (printers != null && !printers.isEmpty()) {
                PrinterResp firstPrinter = printers.get(0);
                printWidth = firstPrinter.getPreferW();
                printHeight = firstPrinter.getPreferH();
                log.debug("从打印机获取尺寸: scenicId={}, printerId={}, width={}, height={}",
                         scenicId, firstPrinter.getId(), printWidth, printHeight);
            }

            // 如果打印机没有配置或配置无效，使用默认值
            if (printWidth == null || printWidth <= 0) {
                printWidth = 1020;
                log.debug("打印机宽度未配置或无效,使用默认值: width={}", printWidth);
            }
            if (printHeight == null || printHeight <= 0) {
                printHeight = 1520;
                log.debug("打印机高度未配置或无效,使用默认值: height={}", printHeight);
            }

            // 使用smartCropAndFill裁剪图片
            File croppedFile = ImageUtils.smartCropAndFill(url, printWidth, printHeight);

            try {
                // 上传裁剪后的图片（使用File版本的uploadFile方法）
                String[] split = url.split("\\.");
                String ext = split.length > 0 ? split[split.length - 1] : "jpg";

                cropUrl = StorageFactory.use().uploadFile(null, croppedFile, "printer", UUID.randomUUID() + "." + ext);

                log.info("照片裁剪成功: memberId={}, scenicId={}, 原图={}, 裁剪后={}, 尺寸={}x{}",
                        memberId, scenicId, url, cropUrl, printWidth, printHeight);
            } finally {
                // 清理临时文件
                if (croppedFile != null && croppedFile.exists()) {
                    croppedFile.delete();
                }
            }
        } catch (Exception e) {
            log.error("照片裁剪失败,使用原图: memberId={}, scenicId={}, url={}", memberId, scenicId, url, e);
            // 出现异常则使用原图
            cropUrl = url;
        }

        entity.setCropUrl(cropUrl);
        entity.setStatus(0);
        printerMapper.addUserPhoto(entity);
        return entity.getId();
    }

    @Override
    public MemberPrintResp getUserPhoto(Long userId, Long scenicId, Long id) {
        return printerMapper.getUserPhoto(userId, scenicId, id);
    }

    @Override
    public int setPhotoCropped(Long memberId, Long scenicId, Long id, String url, String crop) {
        return printerMapper.setPhotoCropped(memberId, scenicId, id, url, crop);
    }

    @Override
    public int setPhotoQuantity(Long memberId, Long scenicId, Long id, Integer quantity) {
        return printerMapper.setPhotoQuantity(memberId, scenicId, id, quantity);
    }

    @Override
    public PriceObj queryPrice(Long memberId, Long scenicId, Long faceId) {
        List<MemberPrintResp> userPhotoList = getUserPhotoList(memberId, scenicId, faceId);

        PriceObj obj = new PriceObj();
        obj.setScenicId(scenicId);
        obj.setGoodsId(faceId);
        obj.setFaceId(faceId);
        obj.setGoodsType(3);

        // 按照 sourceId 分类照片
        // sourceId > 0: 普通照片打印 (PHOTO_PRINT)
        // sourceId == null: 手机照片打印 (PHOTO_PRINT_MU)
        // sourceId == 0: 特效照片打印 (PHOTO_PRINT_FX)
        long normalCount = userPhotoList.stream()
            .filter(item -> Objects.nonNull(item.getQuantity())
                && item.getSourceId() != null && item.getSourceId() > 0)
            .mapToInt(MemberPrintResp::getQuantity)
            .sum();

        long mobileCount = userPhotoList.stream()
            .filter(item -> Objects.nonNull(item.getQuantity())
                && item.getSourceId() == null)
            .mapToInt(MemberPrintResp::getQuantity)
            .sum();

        long effectCount = userPhotoList.stream()
            .filter(item -> Objects.nonNull(item.getQuantity())
                && item.getSourceId() != null && item.getSourceId() == 0)
            .mapToInt(MemberPrintResp::getQuantity)
            .sum();

        long totalCount = normalCount + mobileCount + effectCount;

        if (totalCount == 0) {
            // 如果没有照片，返回零价格
            obj.setPrice(BigDecimal.ZERO);
            obj.setSlashPrice(BigDecimal.ZERO);
            obj.setFree(false);
            return obj;
        }

        // 构建价格计算请求
        PriceCalculationRequest request = new PriceCalculationRequest();
        request.setUserId(memberId);

        // 创建商品项列表
        List<ProductItem> productItems = new ArrayList<>();

        // 添加普通照片打印商品项 (sourceId > 0)
        if (normalCount > 0) {
            ProductItem normalPhotoItem = new ProductItem();
            normalPhotoItem.setProductType(ProductType.PHOTO_PRINT);
            normalPhotoItem.setProductId(scenicId.toString());
            normalPhotoItem.setQuantity(Long.valueOf(normalCount).intValue());
            normalPhotoItem.setPurchaseCount(1);
            normalPhotoItem.setScenicId(scenicId.toString());
            productItems.add(normalPhotoItem);
            log.debug("普通照片打印数量: {}", normalCount);
        }

        // 添加手机照片打印商品项 (sourceId == null)
        if (mobileCount > 0) {
            ProductItem mobilePhotoItem = new ProductItem();
            mobilePhotoItem.setProductType(ProductType.PHOTO_PRINT_MU);
            mobilePhotoItem.setProductId(scenicId.toString());
            mobilePhotoItem.setQuantity(Long.valueOf(mobileCount).intValue());
            mobilePhotoItem.setPurchaseCount(1);
            mobilePhotoItem.setScenicId(scenicId.toString());
            productItems.add(mobilePhotoItem);
            log.debug("手机照片打印数量: {}", mobileCount);
        }

        // 添加特效照片打印商品项 (sourceId == 0)
        if (effectCount > 0) {
            ProductItem effectPhotoItem = new ProductItem();
            effectPhotoItem.setProductType(ProductType.PHOTO_PRINT_FX);
            effectPhotoItem.setProductId(scenicId.toString());
            effectPhotoItem.setQuantity(Long.valueOf(effectCount).intValue());
            effectPhotoItem.setPurchaseCount(1);
            effectPhotoItem.setScenicId(scenicId.toString());
            productItems.add(effectPhotoItem);
            log.debug("特效照片打印数量: {}", effectCount);
        }

        request.setProducts(productItems);

        if (mobileCount > 0) {
            try {
                autoCouponService.autoGrantCoupon(
                        memberId,
                        faceId,
                        scenicId,
                        ProductType.PHOTO_PRINT_MU
                );
            } catch (Exception e) {
                log.warn("自动发券失败，不影响下单流程: memberId={}, faceId={}, scenicId={}, error={}",
                        memberId, faceId, scenicId, e.getMessage());
            }
        }
        request.setAutoUseCoupon(true);
        request.setPreviewOnly(true); // 仅查询价格，不实际使用优惠

        // 使用统一价格计算服务
        PriceCalculationResult result = priceCalculationService.calculatePrice(request);

        // 转换为原有的 PriceObj 格式
        obj.setPrice(result.getFinalAmount());
        obj.setSlashPrice(result.getOriginalAmount());
        obj.setFree(result.getFinalAmount().compareTo(BigDecimal.ZERO) == 0);

        return obj;
    }

    @Override
    public List<Integer> addUserPhotoFromSource(Long memberId, Long scenicId, FromSourceReq req, Long faceId) {
        List<Integer> resultIds = new ArrayList<>();
        req.getIds().forEach(id -> {
            SourceRespVO byId = sourceMapper.getById(id);
            if (byId == null) {
                resultIds.add(null);
                return;
            }

            String url = byId.getUrl();
            MemberPrintEntity entity = new MemberPrintEntity();
            entity.setMemberId(memberId);
            entity.setScenicId(scenicId);
            entity.setFaceId(faceId);
            entity.setSourceId(id);
            entity.setOrigUrl(url);

            // 获取打印尺寸并裁剪图片
            String cropUrl = url; // 默认使用原图
            try {
                // 从打印机表获取尺寸
                Integer printWidth = null;
                Integer printHeight = null;

                List<PrinterResp> printers = printerMapper.listByScenicId(scenicId);
                if (printers != null && !printers.isEmpty()) {
                    PrinterResp firstPrinter = printers.get(0);
                    printWidth = firstPrinter.getPreferW();
                    printHeight = firstPrinter.getPreferH();
                    log.debug("从打印机获取尺寸: scenicId={}, printerId={}, width={}, height={}",
                            scenicId, firstPrinter.getId(), printWidth, printHeight);
                }

                // 如果打印机没有配置或配置无效，使用默认值
                if (printWidth == null || printWidth <= 0) {
                    printWidth = 1020;
                    log.debug("打印机宽度未配置或无效,使用默认值: width={}", printWidth);
                }
                if (printHeight == null || printHeight <= 0) {
                    printHeight = 1520;
                    log.debug("打印机高度未配置或无效,使用默认值: height={}", printHeight);
                }

                // 使用smartCropAndFill裁剪图片
                File croppedFile = ImageUtils.smartCropAndFill(url, printWidth, printHeight);

                try {
                    // 上传裁剪后的图片
                    String[] split = url.split("\\.");
                    String ext = split.length > 0 ? split[split.length - 1] : "jpg";

                    cropUrl = StorageFactory.use().uploadFile(null, croppedFile, "printer", UUID.randomUUID() + "." + ext);

                    log.info("照片裁剪成功: memberId={}, scenicId={}, sourceId={}, 原图={}, 裁剪后={}, 尺寸={}x{}",
                            memberId, scenicId, id, url, cropUrl, printWidth, printHeight);
                } finally {
                    // 清理临时文件
                    if (croppedFile != null && croppedFile.exists()) {
                        croppedFile.delete();
                    }
                }
            } catch (Exception e) {
                log.error("照片裁剪失败,使用原图: memberId={}, scenicId={}, sourceId={}, url={}", memberId, scenicId, id, url, e);
                // 出现异常则使用原图
                cropUrl = url;
            }

            entity.setCropUrl(cropUrl);
            entity.setStatus(0);

            try {
                int rows = printerMapper.addUserPhoto(entity);
                if (rows > 0 && entity.getId() != null) {
                    resultIds.add(entity.getId());
                } else {
                    resultIds.add(null);
                }
            } catch (Exception e) {
                log.error("添加用户照片失败, memberId={}, scenicId={}, sourceId={}", memberId, scenicId, id, e);
                resultIds.add(null);
            }
        });
        return resultIds;
    }

    @Override
    public Map<String, Object> createOrder(Long memberId, Long scenicId, Integer printerId, Long faceId) {
        PrinterEntity printer = null;
        if (printerId == null) {
            List<PrinterResp> printerList = printerMapper.listByScenicId(scenicId);
            if (printerList.size() != 1) {
                throw new BaseException("请选择打印机");
            }
            printerId = printerList.getFirst().getId();
        }
        printer = printerMapper.getById(printerId);
        if (printer == null) {
            throw new BaseException("打印机不存在");
        }
        if (printer.getStatus() != 1) {
            throw new BaseException("打印机已停用");
        }
        if (!printer.getScenicId().equals(scenicId)) {
            throw new BaseException("打印机不属于该景区");
        }
        // 验证照片数量
        List<MemberPrintResp> userPhotoList = getUserPhotoList(memberId, scenicId, faceId);

        // 按照 sourceId 分类照片
        // sourceId > 0: 普通照片打印 (PHOTO_PRINT)
        // sourceId == null: 手机照片打印 (PHOTO_PRINT_MU)
        // sourceId == 0: 特效照片打印 (PHOTO_PRINT_FX)
        long normalCount = userPhotoList.stream()
            .filter(item -> Objects.nonNull(item.getQuantity())
                && item.getSourceId() != null && item.getSourceId() > 0)
            .mapToInt(MemberPrintResp::getQuantity)
            .sum();

        long mobileCount = userPhotoList.stream()
            .filter(item -> Objects.nonNull(item.getQuantity())
                && item.getSourceId() == null)
            .mapToInt(MemberPrintResp::getQuantity)
            .sum();

        long effectCount = userPhotoList.stream()
            .filter(item -> Objects.nonNull(item.getQuantity())
                && item.getSourceId() != null && item.getSourceId() == 0)
            .mapToInt(MemberPrintResp::getQuantity)
            .sum();

        long totalCount = normalCount + mobileCount + effectCount;

        if (totalCount == 0) {
            throw new BaseException("没有可打印的照片");
        }

        OrderEntity order = new OrderEntity();
        Long orderId = SnowFlakeUtil.getLongId();
        redisTemplate.opsForValue().set("printer_size:"+orderId, printer.getPreferPaper(), 60, TimeUnit.SECONDS);
        order.setId(orderId);
        order.setMemberId(memberId);
        order.setFaceId(faceId);
        MemberRespVO member = memberMapper.getById(memberId);
        order.setOpenId(member.getOpenId());
        order.setScenicId(scenicId);
        order.setType(3); // 照片打印类型
        batchSetUserPhotoListToPrinter(memberId, scenicId, printerId);
        List<OrderItemEntity> orderItems = userPhotoList.stream().map(goods -> {
            OrderItemEntity orderItem = new OrderItemEntity();
            orderItem.setOrderId(orderId);
            // member_print
            orderItem.setGoodsId(Long.valueOf(goods.getId()));
            orderItem.setGoodsType(3);
            return orderItem;
        }).collect(Collectors.toList());

        // 使用统一价格计算服务计算最终价格

        PriceCalculationRequest request = new PriceCalculationRequest();
        request.setUserId(memberId);
        request.setScenicId(scenicId);

        // 创建商品项列表
        List<ProductItem> productItems = new ArrayList<>();

        // 添加普通照片打印商品项 (sourceId > 0)
        if (normalCount > 0) {
            ProductItem normalPhotoItem = new ProductItem();
            normalPhotoItem.setProductType(ProductType.PHOTO_PRINT);
            normalPhotoItem.setProductId(scenicId.toString());
            normalPhotoItem.setQuantity(Long.valueOf(normalCount).intValue());
            normalPhotoItem.setPurchaseCount(1);
            normalPhotoItem.setScenicId(scenicId.toString());
            productItems.add(normalPhotoItem);
            log.debug("创建订单-普通照片打印数量: {}", normalCount);
        }

        // 添加手机照片打印商品项 (sourceId == null)
        if (mobileCount > 0) {
            ProductItem mobilePhotoItem = new ProductItem();
            mobilePhotoItem.setProductType(ProductType.PHOTO_PRINT_MU);
            mobilePhotoItem.setProductId(scenicId.toString());
            mobilePhotoItem.setQuantity(Long.valueOf(mobileCount).intValue());
            mobilePhotoItem.setPurchaseCount(1);
            mobilePhotoItem.setScenicId(scenicId.toString());
            productItems.add(mobilePhotoItem);
            log.debug("创建订单-手机照片打印数量: {}", mobileCount);
        }

        // 添加特效照片打印商品项 (sourceId == 0)
        if (effectCount > 0) {
            ProductItem effectPhotoItem = new ProductItem();
            effectPhotoItem.setProductType(ProductType.PHOTO_PRINT_FX);
            effectPhotoItem.setProductId(scenicId.toString());
            effectPhotoItem.setQuantity(Long.valueOf(effectCount).intValue());
            effectPhotoItem.setPurchaseCount(1);
            effectPhotoItem.setScenicId(scenicId.toString());
            productItems.add(effectPhotoItem);
            log.debug("创建订单-特效照片打印数量: {}", effectCount);
        }

        request.setProducts(productItems);
        request.setAutoUseCoupon(true);
        request.setPreviewOnly(false);
        request.setOrderId(String.valueOf(orderId)); // 设置订单ID

        PriceCalculationResult priceResult = priceCalculationService.calculatePrice(request);

        order.setPrice(priceResult.getFinalAmount());
        order.setSlashPrice(priceResult.getOriginalAmount());
        order.setPayPrice(priceResult.getFinalAmount());
        order.setFaceId(faceId);
        if (order.getPayPrice().equals(BigDecimal.ZERO)) {
            order.setStatus(OrderStateEnum.PAID.getState());
            order.setPayAt(new Date());
        } else {
            order.setStatus(OrderStateEnum.UNPAID.getState());
        }
        orderMapper.add(order);
        int addOrderItems = orderMapper.addOrderItems(orderItems);
        if (addOrderItems == NumberConstant.ZERO) {
            log.error("订单明细添加失败");
            throw new BaseException("订单添加失败");
        }
        Map<String, Object> data = new HashMap<>();
        if (order.getPayPrice().compareTo(BigDecimal.ZERO) == 0) {
            orderBiz.paidOrder(order.getId());
            data.put("needPay", false);
        } else {
            WXPayOrderReqVO wxPayOrderReqVO = new WXPayOrderReqVO();
            wxPayOrderReqVO.setOpenId(order.getOpenId())
                    .setMemberId(order.getMemberId())
                    .setOrderSn(order.getId())
                    .setTotalPrice(order.getPayPrice().setScale(2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).intValueExact())
                    .setGoodsName("照片打印")
                    .setDescription("照片打印");
            try {
                data = wxPayService.createOrder(order.getScenicId(), wxPayOrderReqVO);
            } catch (Exception e) {
                throw new BaseException(e);
            }
        }
        data.put("orderId", orderId);
        return data;
    }

    @Override
    public void batchSetUserPhotoListToPrinter(Long memberId, Long scenicId, Integer printerId) {
        printerMapper.updateUserPhotoListToPrinter(memberId, scenicId, printerId);
    }

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    private static final String USER_PHOTO_LIST_TO_PRINTER = "USER_PHOTO_LIST_TO_PRINTER:";
    private static final String PRINTER_INDEX_KEY_PREFIX = "PRINTER_INDEX:";
    private static final int PRINTER_INDEX_EXPIRE_MINUTES = 5;
    private static final int TASK_STATUS_PENDING = 0;
    private static final int TASK_STATUS_PROCESSING = 3;
    private static final int TASK_STATUS_PENDING_REVIEW = 4; // 待审核
    private final Lock syncTaskLock = new ReentrantLock();

    @Override
    public void setUserIsBuyItem(Long memberId, Long id, Long orderId) {
        if (redisTemplate.opsForValue().get(USER_PHOTO_LIST_TO_PRINTER + memberId + ":" + orderId) != null) {
            return;
        }
        redisTemplate.opsForValue().set(USER_PHOTO_LIST_TO_PRINTER + memberId + ":" + orderId, "1", 60, TimeUnit.SECONDS);
        OrderEntity order = orderRepository.getOrder(orderId);
        List<OrderItemEntity> orderItems = orderMapper.getOrderItems(orderId);
        orderItems.forEach(item -> {
            printerMapper.setUserIsBuyItem(memberId, item.getGoodsId(), orderId);
        });
        // 创建打印任务
        List<MemberPrintResp> userPhotoListByOrderId = getUserPhotoListByOrderId(orderId);
        File qrCodeFile = new File("qrCodeFile" + orderId + ".png");
        MpConfigEntity scenicMpConfig = scenicRepository.getScenicMpConfig(order.getScenicId());
        try {
            WxMpUtil.generateWXAQRCode(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), scenicMpConfig.getState(), "pages/my/orderDetailNew?force=1&id="+orderId, "qrCodeFile" + orderId + ".png");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        userPhotoListByOrderId.forEach(item -> {
            PrinterEntity printer = printerMapper.getById(item.getPrinterId());
            // 水印处理逻辑(仅当sourceId不为空时执行)
            String printUrl = item.getCropUrl();
            if (item.getSourceId() != null) {
                try {
                    ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(item.getScenicId());
                    String printWatermarkType = scenicConfig.getString("print_watermark_type");

                    if (StringUtils.isNotBlank(printWatermarkType)) {
                        ImageWatermarkOperatorEnum watermarkType = ImageWatermarkOperatorEnum.getByCode(printWatermarkType);
                        if (watermarkType != null) {
                            // 准备存储适配器
                            IStorageAdapter adapter;
                            String storeType = scenicConfig.getString("store_type");
                            if (storeType != null) {
                                adapter = StorageFactory.get(storeType);
                                String storeConfigJson = scenicConfig.getString("store_config_json");
                                if (StringUtils.isNotBlank(storeConfigJson)) {
                                    adapter.loadConfig(JacksonUtil.parseObject(storeConfigJson, Map.class));
                                }
                            } else {
                                adapter = StorageFactory.use("assets-ext");
                            }

                            // 准备水印处理器
                            IOperator operator = ImageWatermarkFactory.get(watermarkType);

                            // 生成唯一的处理标识符，避免多线程环境下的文件冲突
                            String processId = item.getId() + "_" + UUID.randomUUID().toString();
                            // 下载原图
                            File originalFile = new File("print_" + processId + ".jpg");
                            File watermarkedFile = new File("print_" + processId + "_" + watermarkType.getType() + "." + watermarkType.getPreferFileType());
                            File rotatedOriginalFile = null;
                            File rotatedWatermarkedFile = null;
                            boolean needRotation = false;

                            try {
                                HttpUtil.downloadFile(item.getCropUrl().replace("oss.zhentuai.com", "frametour-assets.oss-cn-shanghai-internal.aliyuncs.com"), originalFile);

                                // 判断图片方向并处理旋转
                                boolean isLandscape = ImageUtils.isLandscape(originalFile);
                                log.info("打印照片方向检测，照片ID: {}, 是否为横图: {}", item.getId(), isLandscape);

                                if (!isLandscape) {
                                    // 竖图需要旋转为横图
                                    needRotation = true;
                                    rotatedOriginalFile = new File("print_" + processId + "_rotated.jpg");
                                    ImageUtils.rotateImage90(originalFile, rotatedOriginalFile);
                                    log.info("竖图已旋转为横图，照片ID: {}", item.getId());
                                }

                                // 处理水印
                                WatermarkInfo watermarkInfo = new WatermarkInfo();
                                watermarkInfo.setScenicLine(scenicConfig.getString("print_watermark_scenic_text", ""));
                                watermarkInfo.setOriginalFile(needRotation ? rotatedOriginalFile : originalFile);
                                watermarkInfo.setWatermarkedFile(watermarkedFile);
                                watermarkInfo.setQrcodeFile(qrCodeFile);
                                watermarkInfo.setDatetime(new Date());
                                watermarkInfo.setDtFormat(scenicConfig.getString("print_watermark_dt_format", "yyyy.MM.dd"));

                                operator.process(watermarkInfo);

                                // 如果之前旋转了,需要将水印图片旋转回去
                                if (needRotation) {
                                    rotatedWatermarkedFile = new File("print_" + processId + "_final_" + watermarkType.getType() + "." + watermarkType.getPreferFileType());
                                    ImageUtils.rotateImage270(watermarkedFile, rotatedWatermarkedFile);
                                    log.info("水印图片已旋转回竖图，照片ID: {}", item.getId());
                                    // 删除中间的横图水印文件
                                    if (watermarkedFile.exists()) {
                                        watermarkedFile.delete();
                                    }
                                    // 将最终的竖图水印文件赋值给watermarkedFile
                                    watermarkedFile = rotatedWatermarkedFile;
                                }

                                // 上传水印图片
                                String watermarkedUrl = adapter.uploadFile(null, watermarkedFile, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());
                                adapter.setAcl(StorageAcl.PUBLIC_READ, StorageConstant.PHOTO_WATERMARKED_PATH, watermarkedFile.getName());

                                printUrl = watermarkedUrl;
                                log.info("水印处理成功，打印照片ID: {}, 水印URL: {}", item.getId(), watermarkedUrl);

                            } catch (Exception e) {
                                log.error("水印处理失败，使用原始照片进行打印。照片ID: {}", item.getId(), e);
                            } finally {
                                // 清理临时文件
                                if (originalFile != null && originalFile.exists()) {
                                    originalFile.delete();
                                }
                                if (rotatedOriginalFile != null && rotatedOriginalFile.exists()) {
                                    rotatedOriginalFile.delete();
                                }
                                if (watermarkedFile != null && watermarkedFile.exists()) {
                                    watermarkedFile.delete();
                                }
                                if (rotatedWatermarkedFile != null && rotatedWatermarkedFile.exists()) {
                                    rotatedWatermarkedFile.delete();
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("获取景区配置失败，使用原始照片进行打印。景区ID: {}, 照片ID: {}", item.getScenicId(), item.getId(), e);
                }
            }

            // 根据数量创建多个打印任务
            Integer quantity = item.getQuantity();
            if (quantity == null || quantity <= 0) {
                quantity = 1; // 默认至少打印1张
            }

            for (int i = 0; i < quantity; i++) {
                // 获取打印机名称（支持轮询）
                String selectedPrinter = getNextPrinter(printer);

                // 根据景区配置决定任务初始状态
                ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(order.getScenicId());
                Boolean purchaseNeedReview = scenicConfig.getBoolean("printer_manual_approve");
                int initialStatus = (purchaseNeedReview != null && purchaseNeedReview)
                                    ? TASK_STATUS_PENDING_REVIEW
                                    : TASK_STATUS_PENDING;

                PrintTaskEntity task = new PrintTaskEntity();
                task.setPrinterId(printer.getId());
                task.setPrinterName(selectedPrinter);
                task.setMpId(item.getId());
                task.setPaper(printer.getPreferPaper());
                task.setStatus(initialStatus);
                task.setUrl(printUrl);
                task.setHeight(printer.getPreferH());
                task.setWidth(printer.getPreferW());
                task.setCreateTime(new Date());
                task.setUpdateTime(new Date());
                printTaskMapper.insertTask(task);
            }
        });
    }

    /**
     * 查询待审核的打印任务
     * @param printerId 打印机ID(可选)
     * @return 待审核任务列表
     */
    @Override
    public List<PrintTaskEntity> getPendingReviewTasks(Integer printerId) {
        return printTaskMapper.queryPendingReviewTasks(printerId);
    }

    /**
     * 更新待审核任务的URL（可用于重新添加水印等操作）
     * @param taskId 任务ID
     * @param url 新的打印URL
     * @return 是否成功
     */
    @Override
    public boolean updatePendingReviewTaskUrl(Integer taskId, String url) {
        if (taskId == null || url == null || url.trim().isEmpty()) {
            return false;
        }
        int rows = printTaskMapper.updateTaskUrl(taskId, url);
        return rows > 0;
    }

    /**
     * 批准待审核任务，下发到打印队列
     * @param taskIds 任务ID列表
     * @return 成功数量
     */
    @Override
    public int approvePrintTasks(List<Integer> taskIds) {
        if (taskIds == null || taskIds.isEmpty()) {
            return 0;
        }
        // 将状态从4（待审核）改为0（待处理）
        return printTaskMapper.batchUpdateStatus(taskIds, TASK_STATUS_PENDING);
    }

    /**
     * 拒绝待审核任务（取消打印）
     * @param taskIds 任务ID列表
     * @return 成功数量
     */
    @Override
    public int rejectPrintTasks(List<Integer> taskIds) {
        if (taskIds == null || taskIds.isEmpty()) {
            return 0;
        }
        // 将状态从4（待审核）改为5（已取消）
        return printTaskMapper.batchUpdateStatus(taskIds, 5);
    }

    @Override
    public FaceRecognizeResp useSample(Long userId, Long sampleId) {
        // 1. 查询 faceSample 获取其 URL
        FaceSampleEntity faceSample = faceSampleMapper.getEntity(sampleId);
        SourceEntity sourceEntity = sourceMapper.getBySampleIdAndType(sampleId, 2);
        if (faceSample == null) {
            throw new BaseException("人脸样本不存在");
        }
        
        String faceUrl = faceSample.getFaceUrl();
        if (StringUtils.isBlank(faceUrl)) {
            throw new BaseException("人脸样本URL为空");
        }
        
        Long scenicId = faceSample.getScenicId();
        
        // 2. 检查face数据库中有没有同用户、同URL的face记录
        FaceEntity existingFace = null;
        Long faceId = null;
        
        // 查询该用户在该景区的所有人脸记录
        List<FaceRespVO> userFaces = faceMapper.listByScenicAndUserId(scenicId.toString(), userId);
        
        // 查找是否存在相同URL的记录
        for (FaceRespVO faceResp : userFaces) {
            if (faceUrl.equals(faceResp.getFaceUrl())) {
                existingFace = faceMapper.get(faceResp.getId());
                faceId = existingFace.getId();
                break;
            }
        }
        
        // 3. 如果不存在,则新建一个face记录
        if (existingFace == null) {
            faceId = SnowFlakeUtil.getLongId();
            FaceEntity newFace = new FaceEntity();
            newFace.setId(faceId);
            newFace.setCreateAt(new Date());
            newFace.setScenicId(scenicId);
            newFace.setMemberId(userId);
            newFace.setFaceUrl(faceUrl);
            faceMapper.add(newFace);
            
            log.info("创建新的face记录, userId: {}, sampleId: {}, faceId: {}, faceUrl: {}", 
                     userId, sampleId, faceId, faceUrl);
        } else {
            log.info("使用已存在的face记录, userId: {}, sampleId: {}, faceId: {}, faceUrl: {}", 
                     userId, sampleId, faceId, faceUrl);
        }
        
        // 4. 返回结果
        FaceRecognizeResp resp = new FaceRecognizeResp();
        resp.setUrl(faceUrl);
        resp.setFaceId(faceId);
        resp.setScenicId(scenicId);
        try {
            faceService.matchFaceId(faceId);
            if (existingFace == null) {
                autoAddPhotosToPreferPrint(faceId);
            }
        } catch (Exception e) {
            // 人脸匹配失败不可以阻止正常流程
            log.error("人脸匹配失败", e);
        }
        if (sourceEntity != null && existingFace == null) {
            List<MemberPrintResp> userPhotoList = getUserPhotoList(userId, scenicId, faceId);
            boolean noneMatch = userPhotoList.stream()
                    .noneMatch(item -> Strings.CI.equals(item.getOrigUrl(), sourceEntity.getUrl()));
            if (noneMatch) {
                addUserPhoto(userId, scenicId, sourceEntity.getUrl(), faceId, sourceEntity.getId());
            }
        }
        return resp;
    }

    /**
     * 自动将人脸关联的照片添加到优先打印列表
     * 根据景区和设备配置自动添加type=2的照片到用户打印列表
     *
     * @param faceId 人脸ID
     */
    @Override
    public void autoAddPhotosToPreferPrint(Long faceId) {
        try {
            // 1. 获取人脸信息
            FaceEntity face = faceRepository.getFace(faceId);
            if (face == null) {
                log.warn("人脸不存在,无法自动添加打印: faceId={}", faceId);
                return;
            }

            Long scenicId = face.getScenicId();
            Long memberId = face.getMemberId();

            // 2. 获取景区配置
            ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
            if (scenicConfig == null) {
                log.warn("景区配置不存在,跳过自动添加打印: scenicId={}", scenicId);
                return;
            }

            // 3. 检查景区是否启用打印功能
            Boolean printEnable = scenicConfig.getBoolean("print_enable");
            if (printEnable == null || !printEnable) {
                log.debug("景区未启用打印功能,跳过自动添加: scenicId={}", scenicId);
                return;
            }

            // 4. 查询该faceId关联的所有type=2的照片
            List<SourceEntity> imageSources = sourceMapper.listImageSourcesByFaceId(faceId);
            if (imageSources == null || imageSources.isEmpty()) {
                log.debug("该人脸没有关联的照片,跳过自动添加: faceId={}", faceId);
                return;
            }

            // 5. 按照deviceId分组处理
            Map<Long, List<SourceEntity>> sourcesByDevice = imageSources.stream()
                    .filter(source -> source.getDeviceId() != null)
                    .collect(Collectors.groupingBy(SourceEntity::getDeviceId));

            // 使用原子计数器统计成功添加的数量
            AtomicInteger totalAdded = new AtomicInteger(0);

            // 创建异步任务列表
            List<CompletableFuture<Void>> futures = new ArrayList<>();

            for (Map.Entry<Long, List<SourceEntity>> entry : sourcesByDevice.entrySet()) {
                Long deviceId = entry.getKey();
                List<SourceEntity> deviceSources = entry.getValue();

                // 为每个设备创建一个异步任务
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    try {
                        // 6. 获取设备配置
                        DeviceConfigManager deviceConfig = deviceRepository.getDeviceConfigManager(deviceId);
                        if (deviceConfig == null) {
                            log.debug("设备配置不存在,跳过该设备: deviceId={}", deviceId);
                            return;
                        }

                        // 7. 检查是否启用优先打印
                        Boolean preferPrintEnable = deviceConfig.getBoolean("prefer_print_enable");
                        if (preferPrintEnable == null || !preferPrintEnable) {
                            log.debug("设备未启用优先打印,跳过: deviceId={}", deviceId);
                            return;
                        }

                        // 8. 获取优先打印数量配置
                        Integer preferPrintCount = deviceConfig.getInteger("prefer_print_count");
                        if (preferPrintCount == null) {
                            log.debug("设备未配置优先打印数量,跳过: deviceId={}", deviceId);
                            return;
                        }

                        // 9. 根据配置添加照片到打印列表
                        List<SourceEntity> sourcesToAdd;
                        if (preferPrintCount > 0) {
                            // 如果大于0,按照数量限制添加
                            sourcesToAdd = deviceSources.stream()
                                    .limit(preferPrintCount)
                                    .collect(Collectors.toList());
                            log.info("设备{}配置优先打印{}张,实际添加{}张",
                                    deviceId, preferPrintCount, sourcesToAdd.size());
                        } else {
                            // 如果小于等于0,添加该设备的所有照片
                            sourcesToAdd = deviceSources;
                            log.info("设备{}配置优先打印所有照片,实际添加{}张",
                                    deviceId, sourcesToAdd.size());
                        }

                        // 10. 批量添加到打印列表
                        int deviceAdded = 0;
                        for (SourceEntity source : sourcesToAdd) {
                            try {
                                addUserPhoto(memberId, scenicId, source.getUrl(), faceId, source.getId());
                                deviceAdded++;
                            } catch (Exception e) {
                                log.warn("添加照片到打印列表失败: sourceId={}, url={}, error={}",
                                        source.getId(), source.getUrl(), e.getMessage());
                            }
                        }

                        // 累加成功添加的数量
                        totalAdded.addAndGet(deviceAdded);

                    } catch (Exception e) {
                        log.error("处理设备{}的照片添加任务失败: deviceId={}", deviceId, deviceId, e);
                    }
                }, preferPrintExecutor);

                futures.add(future);
            }

            // 等待所有任务完成
            try {
                CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
            } catch (Exception e) {
                log.error("等待照片添加任务完成时发生异常: faceId={}", faceId, e);
            }

            if (totalAdded.get() > 0) {
                log.info("自动添加打印完成: faceId={}, 成功添加{}张照片", faceId, totalAdded.get());
            } else {
                log.debug("自动添加打印完成: faceId={}, 无符合条件的照片", faceId);
            }

        } catch (Exception e) {
            // 出现异常则放弃,不影响主流程
            log.error("自动添加打印失败,已忽略: faceId={}", faceId, e);
        }
    }
    /**
     * 获取下一个要使用的打印机名称（轮询逻辑）
     * 
     * @param printer 打印机实体
     * @return 选中的打印机名称
     */
    private String getNextPrinter(PrinterEntity printer) {
        String usePrinter = printer.getUsePrinter();
        if (StringUtils.isBlank(usePrinter)) {
            log.warn("打印机 {} 没有配置 usePrinter", printer.getId());
            return "";
        }

        // 分割打印机列表
        String[] printers = usePrinter.split("\\|");
        if (printers.length == 0) {
            log.warn("打印机 {} 的 usePrinter 配置为空", printer.getId());
            return "";
        }

        // 如果只有一个打印机，直接返回
        if (printers.length == 1) {
            return printers[0].trim();
        }

        // 从 Redis 原子递增获取索引
        String redisKey = PRINTER_INDEX_KEY_PREFIX + printer.getId();
        Long incrementedValue = redisTemplate.opsForValue().increment(redisKey);
        
        if (incrementedValue == null) {
            log.warn("Redis increment 操作失败，打印机ID: {}", printer.getId());
            incrementedValue = 1L;
        }
        
        // 每次递增后都重新设置过期时间为 5 分钟
        redisTemplate.expire(redisKey, PRINTER_INDEX_EXPIRE_MINUTES, TimeUnit.MINUTES);
        
        // 对打印机数量取模得到当前索引
        int currentIndex = (int) ((incrementedValue - 1) % printers.length);
        
        // 获取当前打印机
        String selectedPrinter = printers[currentIndex].trim();

        log.debug("打印机 {} 选择了第 {} 个打印机: {} (递增值: {})", printer.getId(), currentIndex, selectedPrinter, incrementedValue);

        return selectedPrinter;
    }
}
