package com.scm.contract.service.apply;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.scm.contract.dao.apply.LabelApplicationDao;
import com.scm.contract.model.apply.DictionaryTagType;
import com.scm.contract.model.apply.LabelApplication;
import com.scm.contract.model.apply.LabelApplicationDataImport;
import com.scm.contract.model.apply.LabelApplicationDetail;
import com.scm.contract.model.management.Materiel;
import com.scm.contract.model.management.Provider;
import com.scm.contract.model.management.TagData;
import com.scm.contract.model.print.PrintCode;
import com.scm.contract.model.print.ReprintCode;
import com.scm.contract.service.management.MaterielService;
import com.scm.contract.service.management.ProviderService;
import com.scm.contract.service.management.TagDataService;
import com.scm.contract.service.print.PrintCodeService;
import com.scm.contract.service.print.ReprintCodeService;
import com.scm.contract.tools.OutSnowflakeIdGenerator;
import com.scm.contract.tools.Tools;
import com.scm.contract.tools.Validator;
import com.set.direwolf.core.entity.User;
import com.set.direwolf.core.mybatis.CrudService;
import com.set.direwolf.core.mybatis.Page;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

import static com.scm.contract.tools.QcExcelUtil.*;

/**
 * @author zuo
 * @date 2024/6/4 17:46
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class LabelApplicationService extends CrudService<LabelApplicationDao, LabelApplication, String> {

    @Autowired
    private DictionaryTagTypeService tagTypeService;

    @Autowired
    private MaterielService materielService;

    @Autowired
    private ProviderService providerService;

    @Autowired
    private LabelApplicationDetailService detailService;

    @Autowired
    private OutSnowflakeIdGenerator outSnowflakeIdGenerator;


    @Autowired
    private TagDataService tagDataService;

    @Autowired
    private ReprintCodeService reprintCodeService;

    @Autowired
    private PrintCodeService printCodeService;


    public void setName(List<LabelApplication> list, Boolean isHaveDetail) {
        if (CollectionUtils.isNotEmpty(list)) {
            List<String> labelApplicationIds = new ArrayList<>();
            Set<String> providerIdSet = new HashSet<>();

            for (LabelApplication labelApplication : list) {
                labelApplicationIds.add(labelApplication.getId());
                String providerId = labelApplication.getProviderId();
                if (StringUtils.isNotBlank(providerId)) {
                    providerIdSet.add(providerId);
                }
            }

            //获取供应商信息Map
            Map<String, Provider> providerMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(providerIdSet)) {
                List<Provider> providers = providerService.listByIds(new ArrayList<>(providerIdSet));
                if (CollectionUtils.isNotEmpty(providers)) {
                    for (Provider provider : providers) {
                        providerMap.put(provider.getId(), provider);
                    }
                }
            }

            //获取从表信息Map
            Map<String, List<LabelApplicationDetail>> detailMap = new HashMap<>();
            if (CollectionUtils.isNotEmpty(labelApplicationIds)) {
                List<LabelApplicationDetail> details = detailService.getListByLabelApplicationIds(labelApplicationIds);
                if (CollectionUtils.isNotEmpty(details)) {
                    for (LabelApplicationDetail detail : details) {
                        String labelApplicationId = detail.getLabelApplicationId();
                        if (!detailMap.containsKey(labelApplicationId)) {
                            detailMap.put(labelApplicationId, new ArrayList<>());
                        }
                        detailMap.get(labelApplicationId).add(detail);
                    }
                }
            }

            for (LabelApplication labelApplication : list) {
                //设置供应商名字
                String providerId = labelApplication.getProviderId();
                if (StringUtils.isNotBlank(providerId)) {
                    Provider provider = providerMap.getOrDefault(providerId, new Provider());
                    labelApplication.setProviderName(provider.getName());
                }

                //设置总额
                String id = labelApplication.getId();
                List<LabelApplicationDetail> details = detailMap.get(id);
                if (CollectionUtils.isNotEmpty(details)) {
                    Double amountSum = null;
                    Long tagNumber = null;
                    for (LabelApplicationDetail detail : details) {
                        Double amount = detail.getAmount();
                        if (!Objects.isNull(amount)) {
                            if (Objects.isNull(amountSum)) {
                                amountSum = amount;
                            } else {
                                amountSum += amount;
                            }
                        }
                        Long number = detail.getNumber();
                        if (!Objects.isNull(number)) {
                            if (Objects.isNull(tagNumber)) {
                                tagNumber = number;
                            } else {
                                tagNumber += number;
                            }
                        }
                    }
                    if (!Objects.isNull(amountSum)) {
                        amountSum = Tools.digitHalfEven(amountSum, 2);
                    }
                    labelApplication.setAmount(amountSum);
                    labelApplication.setTagNumber(tagNumber);
                    if (isHaveDetail) {
                        labelApplication.setDetails(details);
                    }
                }
            }
        }
    }

    /**
     * 分页查询
     *
     * @param page
     * @param entity
     * @return
     */
    @Override
    public Page<LabelApplication> findPage(Page<LabelApplication> page, LabelApplication entity) {
        entity.setPage(page);
        page.setList(this.dao.findList(entity));
        List<LabelApplication> list = page.getList();
        setName(list, false);
        return page;
    }

    public List<LabelApplication> getListByIds(List<String> ids) {
        return this.dao.getListByIds(ids);
    }

    /**
     * 支付确认，修改成已支付
     *
     * @param ids 需确认的id
     */
    @Transactional
    public synchronized void confirmPay(List<String> ids) {
        List<LabelApplication> list = this.dao.getListByIds(ids);
        if (CollectionUtils.isNotEmpty(list)) {
            list = list.stream().filter(labelApplication -> "1".equals(labelApplication.getTagApplyStateId())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(list)) {
                List<String> idList = list.stream().map(LabelApplication::getId).collect(Collectors.toList());
                this.dao.tagApplyStateIdUpdate(idList, "2");
                tagDataService.saveOrUpdateBash(list, null, null, true);
            }
        }
    }

    @Transactional
    public synchronized Boolean confirmOrder(List<String> ids) {
        List<LabelApplication> list = this.dao.getListByIds(ids);
        if (CollectionUtils.isNotEmpty(list)) {
            Date date = new Date();
            list = list.stream().filter(labelApplication -> "0".equals(labelApplication.getTagApplyStateId())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(list)) {
                setName(list, true);
                //获取每种标签的剩余可使用数量的MAP
                Map<String, Long> surplusNumberMap = tagDataService.getSurplusNumber();
                Map<String, String> tagTypeNameMap = new HashMap<>();
                for (LabelApplication labelApplication : list) {
                    labelApplication.setOrderNo(outSnowflakeIdGenerator.generateId());
                    labelApplication.setTagApplyStateId("1");
                    labelApplication.setDataTime(date);
                    List<LabelApplicationDetail> details = labelApplication.getDetails();
                    for (LabelApplicationDetail detail : details) {
                        Long number = detail.getNumber();
                        String tagTypeId = detail.getTagTypeId();
                        String tagTypeName = detail.getTagTypeName();
                        tagTypeNameMap.put(tagTypeId, tagTypeName);
                        surplusNumberMap.put(tagTypeId, surplusNumberMap.getOrDefault(tagTypeId, 0L) - number);
                    }
                }
                for (Map.Entry<String, Long> entry : surplusNumberMap.entrySet()) {
                    Long value = entry.getValue();
                    if (value < 0) {
                        String key = entry.getKey();
                        String name = tagTypeNameMap.get(key);
                        throw new RuntimeException(name + "库存不足");
                    }
                }
                this.dao.updateListById(list);
                tagDataService.saveOrUpdateBash(list, null, null, true);
            }
        }
        return true;
    }

    @Transactional
    public synchronized Boolean updateConfirmOrder(LabelApplication entity) {
        update(entity);
        String id = entity.getId();
        return confirmOrder(Collections.singletonList(id));
    }

    /**
     * 按供应商导出模版
     *
     * @param providerId 供应商id
     * @return
     */
    public Map<String, Object> getTemplate(String providerId) {
        Materiel materiel = new Materiel();
        materiel.setProviderId(providerId);
        //供应商对应的物料信息
        List<Materiel> materiels = materielService.findList(materiel);

        Provider provider = providerService.get(providerId);
        String providerName = provider.getName();
        //在内存中保留100行，超过的行将刷新到磁盘
        Workbook wb = new XSSFWorkbook();
        //设置sheet
        Sheet sh = wb.createSheet(providerName);
        // 设置 excel 的默认宽度为12个字符的宽度
        sh.setDefaultColumnWidth(12);
        sh.setColumnWidth(3, 50 * 256);
        sh.setColumnWidth(6, 15 * 256);
        //创建样式对象
        CellStyle styleHeadLock = getStyle(wb);
        styleHeadLock.setLocked(true);
        styleHeadLock.setWrapText(true);
        CellStyle styleHeadLock1 = getStyle(wb);
        styleHeadLock1.setLocked(true);
        styleHeadLock1.setWrapText(true);
        Font font = wb.createFont();
        font.setFontName("等线");
        font.setBold(true);
        font.setColor(Font.COLOR_RED);
        styleHeadLock1.setFont(font);
        CellStyle styleLock = getStyle2(wb);
        styleLock.setLocked(true);
        CellStyle styleDateLock = getStyle2(wb);
        styleDateLock.setLocked(true);
        styleDateLock.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat("yyyy/MM/dd"));
        CellStyle style = getStyle2(wb);
        style.setLocked(false);
        CellStyle styleDate = getStyle2(wb);
        styleDate.setLocked(false);
        styleDate.setDataFormat(wb.getCreationHelper().createDataFormat().getFormat("yyyy/MM/dd"));
        sh.setColumnHidden(0, true);
        int rowNumb = 0;
        sh.protectSheet("more123");
        /**
         * 表头
         */
        Row row0 = sh.createRow(rowNumb++);
        setCell(row0, 0, "物料id（隐藏项,请勿修改）", styleHeadLock);
        setCell(row0, 1, "物料编码", styleHeadLock);
        setCell(row0, 2, "商品编码", styleHeadLock);
        setCell(row0, 3, "商品名称", styleHeadLock);
        setCell(row0, 4, "最小包装单元", styleHeadLock);
        setCell(row0, 5, "标签数量（请改写数字）", styleHeadLock1);
        setCell(row0, 6, "预期收货时间（请填写 YYYY/MM/DD格式）", styleHeadLock1);
        setCell(row0, 7, "申领人员（请填写一位人员姓名）", styleHeadLock1);
        setCell(row0, 8, "联系电话（请填写申领人员联系电话）", styleHeadLock1);
        setCell(row0, 9, "邮箱（请填写申领人员邮箱）", styleHeadLock1);
        setCell(row0, 10, "地址（请填写标签收货地址）", styleHeadLock1);

        for (Materiel materiel1 : materiels) {
            String materielCode = materiel1.getMaterielCode();
            String goodsCode = materiel1.getGoodsCode();
            Integer minimumPackingNumber = materiel1.getMinimumPackingNumber();
            String name = materiel1.getGoodsName();
            String id = materiel1.getId();
            Row row = sh.createRow(rowNumb++);

            setCell(row, 0, id, styleLock);
            setCell(row, 1, materielCode, styleLock);
            setCell(row, 2, goodsCode, styleLock);
            setCell(row, 3, name, styleLock);
            setCell(row, 4, minimumPackingNumber, styleLock);
            setCell(row, 5, 0, style);
            setCell(row, 6, "", styleDate);
            setCell(row, 7, "", style);
            setCell(row, 8, "", style);
            setCell(row, 9, "", style);
            setCell(row, 10, "", style);
        }
//        List<DictionaryTagType> tagTypes = tagTypeService.list();
//
//        // 创建下拉选择框的选项列表
//        String[] tagTypeNames = tagTypes.stream().map(DictionaryTagType::getName).toArray(String[]::new);
//
//        // 设置数据有效性（下拉选择框）
//        DataValidationHelper helper = sh.getDataValidationHelper();
//        DataValidationConstraint constraint = helper.createExplicitListConstraint(tagTypeNames);
//        CellRangeAddressList addressList = new CellRangeAddressList(1, 100, 3, 3); // 第一列第1到100行
//        DataValidation dataValidation = helper.createValidation(constraint, addressList);
//        dataValidation.createErrorBox("Error", "You must select a valid option!");
//        dataValidation.setShowErrorBox(true);
//        sh.addValidationData(dataValidation);
        Map<String, Object> map = new HashMap<>();
        map.put("wb", wb);
        map.put("providerName", providerName);
        return map;
    }

    /**
     * 导入标签申领信息
     *
     * @param dataImport
     * @return
     */
    @Transactional
    public synchronized LabelApplication importData(LabelApplicationDataImport dataImport) {
        MultipartFile file = dataImport.getFile();
        User user = Tools.getUser();

        List<LabelApplicationDetail> details = new ArrayList<>();
        LabelApplication labelApplication = new LabelApplication();
        String idStr = IdWorker.getIdStr();
        Date date = new Date();
        try {
            int totalRowNum = 0;
//            Workbook workbook = WorkbookFactory.create(fileInputStream, password);
            XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
            XSSFSheet sheet = workbook.getSheetAt(0);
            if (Objects.isNull(sheet)) throw new RuntimeException("空表,不能进行导入");
            totalRowNum = sheet.getLastRowNum();
            XSSFRow headRow = sheet.getRow(0);
            if (Objects.isNull(headRow)) throw new RuntimeException("空表,不能进行导入");

            //申领日期
            labelApplication.setDataTime(date);
            //操作员 | 操作员名称
            labelApplication.setOperatorId(user.getId());
            labelApplication.setOperatorName(user.getNickName());
            //标签申领状态
            labelApplication.setTagApplyStateId("0");
            //id
            labelApplication.setId(idStr);
            for (int i = 1; i <= totalRowNum; i++) {
                XSSFRow row = sheet.getRow(i);
                LabelApplicationDetail detail = new LabelApplicationDetail();
                //标签数量
                XSSFCell cell5 = row.getCell(5);
                long number;
                try {
                    number = (long) cell5.getNumericCellValue();
                } catch (Exception e) {
                    throw new RuntimeException("标签数量必须填写数字，不申请可填0（第" + (i + 1) + "行)");
                }
                if (number > 0) {
                    detail.setNumber(number);
                    //物料id
                    XSSFCell cell0 = row.getCell(0);
                    if (Objects.isNull(cell0) || StringUtils.isBlank(cell0.getStringCellValue())) {
                        throw new RuntimeException("请使用下载原始模版填写");
                    }
                    String materielId = cell0.getStringCellValue();
                    detail.setMaterielId(materielId);
                    //收货日期
                    XSSFCell cell6 = row.getCell(6);
                    if (Objects.isNull(cell6)) throw new RuntimeException("缺少收货日期（第" + (i + 1) + "行)");
                    CellType cellTypeEnum6 = cell6.getCellTypeEnum();
                    Date expectedReceiptDate = null;
                    if (cellTypeEnum6 == CellType.NUMERIC) {
                        expectedReceiptDate = cell6.getDateCellValue();
                    } else if (cellTypeEnum6 == CellType.STRING) {
                        String expectedReceiptDateStr = cell6.getStringCellValue();
                        if (StringUtils.isBlank(expectedReceiptDateStr))
                            throw new RuntimeException("缺少收货日期（第" + (i + 1) + "行)");
                        try {
                            expectedReceiptDate = DateUtils.parseDate(expectedReceiptDateStr, "yyyy/MM/dd");
                        } catch (ParseException e) {
                            throw new RuntimeException("时间格式错误（第" + (i + 1) + "行)");
                        }
                    }
                    if (Objects.isNull(expectedReceiptDate))
                        throw new RuntimeException("缺少收货日期（第" + (i + 1) + "行)");
//                    Calendar ca = Calendar.getInstance();
//                    ca.set(Calendar.HOUR_OF_DAY,0);
//                    ca.set(Calendar.MINUTE,0);
//                    ca.set(Calendar.SECOND,0);
//                    ca.set(Calendar.MILLISECOND,0);
//                    if (ca.getTime().getTime() > expectedReceiptDate.getTime()) throw new RuntimeException("收货日期不可早于今天");
                    detail.setExpectedReceiptDate(expectedReceiptDate);
                    //申领人员
                    XSSFCell cell7 = row.getCell(7);
                    if (Objects.isNull(cell7)) throw new RuntimeException("申领人员填写错误（第" + (i + 1) + "行)");
                    CellType cellTypeEnum7 = cell7.getCellTypeEnum();
                    if (cellTypeEnum7 != CellType.STRING) {
                        throw new RuntimeException("申领人员填写错误（第" + (i + 1) + "行)");
                    }
                    String applicantName = cell7.getStringCellValue();
                    if (StringUtils.isBlank(applicantName))
                        throw new RuntimeException("缺少申领人员（第" + (i + 1) + "行)");
                    detail.setApplicantName(applicantName);


                    //电话
                    XSSFCell cell8 = row.getCell(8);
                    if (Objects.isNull(cell8)) throw new RuntimeException("请正确填写联系电话（第" + (i + 1) + "行)");
                    CellType cellTypeEnum8 = cell8.getCellTypeEnum();
                    String phone = null;
                    if (cellTypeEnum8 == CellType.NUMERIC) {
                        // 使用DataFormatter来格式化单元格数据，确保不以科学计数法显示
                        DataFormatter dataFormatter = new DataFormatter();
                        phone = dataFormatter.formatCellValue(cell8);
                    } else if (cellTypeEnum8 == CellType.STRING) {
                        phone = cell8.getStringCellValue();
                    }
                    boolean validPhone = Validator.isValidPhone(phone);
                    if (!validPhone) throw new RuntimeException("请正确填写联系电话（第" + (i + 1) + "行)");
                    detail.setPhone(phone);

                    //邮箱
                    XSSFCell cell9 = row.getCell(9);
                    if (Objects.isNull(cell9)) throw new RuntimeException("请正确填写邮箱（第" + (i + 1) + "行)");
                    CellType cellTypeEnum9 = cell9.getCellTypeEnum();
                    if (cellTypeEnum9 != CellType.STRING) {
                        throw new RuntimeException("请正确填写邮箱（第" + (i + 1) + "行)");
                    }
                    String mail = cell9.getStringCellValue();
                    boolean validMail = Validator.isEmailValid(mail);
                    if (!validMail) throw new RuntimeException("请正确填写邮箱（第" + (i + 1) + "行)");
                    detail.setMail(mail);

                    //收货地址
                    XSSFCell cell10 = row.getCell(10);
                    if (Objects.isNull(cell10)) throw new RuntimeException("缺少收货地址（第" + (i + 1) + "行)");
                    CellType cellTypeEnum10 = cell10.getCellTypeEnum();
                    String address = null;
                    if (cellTypeEnum10 == CellType.NUMERIC) {
                        address = String.valueOf(cell10.getNumericCellValue());
                    } else if (cellTypeEnum10 == CellType.STRING) {
                        address = cell10.getStringCellValue();
                    }
                    if (StringUtils.isBlank(address)) throw new RuntimeException("缺少收货地址（第" + (i + 1) + "行)");
                    detail.setAddress(address);
                    detail.setIsSend(false);
                    //放入List
                    details.add(detail);
                }
            }
            List<String> materielIds = details.stream().map(LabelApplicationDetail::getMaterielId).distinct().collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(materielIds)) {
                //获取物料信息
                List<Materiel> materiels = materielService.listByIds(materielIds);
                if (materiels.size() != materielIds.size()) {
                    throw new RuntimeException("请使用下载原始模版填写");
                }
                Set<String> tagTypeSet = new HashSet<>();
                Map<String, Materiel> materielMap = new HashMap<>();
                String providerId = null;
                for (Materiel materiel : materiels) {
                    materielMap.put(materiel.getId(), materiel);
                    tagTypeSet.add(materiel.getTagTypeId());
                    if (StringUtils.isBlank(providerId)) {
                        providerId = materiel.getProviderId();
                    }
                    if (!providerId.equals(materiel.getProviderId())) {
                        throw new RuntimeException("不能多个供应商的商品一起导入");
                    }
                }
                //获取标签类型信息
                List<DictionaryTagType> tagTypes = tagTypeService.listByIds(new ArrayList<>(tagTypeSet));
                Map<String, DictionaryTagType> tagTypeMap = new HashMap<>();
                for (DictionaryTagType tagType : tagTypes) {
                    tagTypeMap.put(tagType.getId(), tagType);
                }
                for (LabelApplicationDetail detail : details) {
                    String materielId = detail.getMaterielId();
                    Materiel materiel = materielMap.getOrDefault(materielId, new Materiel());
                    detail.setGoodsCode(materiel.getGoodsCode());
                    detail.setGoodsName(materiel.getGoodsName());
                    detail.setMaterielCode(materiel.getMaterielCode());
                    detail.setMaterielDescribe(materiel.getMaterielDescribe());
                    detail.setMinimumPackingNumber(materiel.getMinimumPackingNumber());
                    detail.setMinimumPackingUnit(materiel.getMinimumPackingUnit());

                    String tagTypeId = materiel.getTagTypeId();
                    detail.setTagTypeId(tagTypeId);
                    DictionaryTagType tagType = tagTypeMap.getOrDefault(tagTypeId, new DictionaryTagType());
                    detail.setUnitPrice(tagType.getPrice());

                    detail.setLabelApplicationId(idStr);
                }
                labelApplication.setProviderId(providerId);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        if (CollectionUtils.isNotEmpty(details)) {
            detailService.saveList(details);
            this.dao.saveList(Collections.singletonList(labelApplication));
            tagDataService.saveOrUpdateBash(Collections.singletonList(labelApplication), null, null, true);
            return getById(labelApplication.getId(), true);
        }
        return new LabelApplication();
    }

    public LabelApplication getById(String id, Boolean isHaveDetail) {
        LabelApplication labelApplication = this.dao.getById(id);
        if (!Objects.isNull(labelApplication)) {
            setName(Collections.singletonList(labelApplication), isHaveDetail);
        }
        List<LabelApplicationDetail> details = labelApplication.getDetails();
        if (CollectionUtils.isNotEmpty(details)) {
            details.sort(Comparator.comparing(LabelApplicationDetail::getIsSend)
                    .thenComparing(LabelApplicationDetail::getApplicantName)
                    .thenComparing(LabelApplicationDetail::getAddress)
                    .thenComparing(LabelApplicationDetail::getPhone)
                    .thenComparing(LabelApplicationDetail::getExpectedReceiptDate));
        }
        return labelApplication;
    }

    public LabelApplication orderById(String id, Boolean isHaveDetail) {
        LabelApplication labelApplication = this.dao.getById(id);
        if (!Objects.isNull(labelApplication)) {
            setName(Collections.singletonList(labelApplication), isHaveDetail);
        }
        List<LabelApplicationDetail> details = labelApplication.getDetails();
        if (CollectionUtils.isNotEmpty(details)) {
            Map<String, LabelApplicationDetail> detailMap = new LinkedHashMap<>();
            for (LabelApplicationDetail detail : details) {
                String tagTypeId = detail.getTagTypeId();
                Long number = detail.getNumber();
                Double amount = detail.getAmount();
                Double unitPrice = detail.getUnitPrice();
                String tagTypeName = detail.getTagTypeName();
                if (!detailMap.containsKey(tagTypeId)) {
                    LabelApplicationDetail detail1 = new LabelApplicationDetail();
                    detail1.setTagTypeId(tagTypeId);
                    detail1.setTagTypeName(tagTypeName);
                    detail1.setNumber(number);
                    detail1.setAmount(amount);
                    detail1.setUnitPrice(unitPrice);
                    detailMap.put(tagTypeId, detail1);
                } else {
                    LabelApplicationDetail detail1 = detailMap.get(tagTypeId);
                    detail1.setAmount(detail1.getAmount() + amount);
                    detail1.setNumber(detail1.getNumber() + number);
                }
            }
            List<LabelApplicationDetail> details1 = new ArrayList<>(detailMap.values());
            for (LabelApplicationDetail detail : details1) {
                Long number = detail.getNumber();
                Double amount = Tools.digitHalfEven(detail.getAmount(), 2);
                Double unitPrice = Tools.digitHalfEven(amount / number, 2);
                detail.setNumber(number);
                detail.setAmount(amount);
                detail.setUnitPrice(unitPrice);
            }
            labelApplication.setDetails(details1);
        }
        return labelApplication;
    }

    @Transactional
    public synchronized Boolean editShippingMethod(LabelApplication entity) {
        String id = entity.getId();
        LabelApplication labelApplication = getById(id, false);
        String tagApplyStateId = labelApplication.getTagApplyStateId();
        if (!"5".equals(tagApplyStateId)) throw new RuntimeException("当前状态未处于待发货状态，不能修改");

        List<LabelApplicationDetail> oldDetails = detailService.getListByLabelApplicationId(id);
        if (CollectionUtils.isNotEmpty(oldDetails)) {
            List<LabelApplicationDetail> details = entity.getDetails();
            List<LabelApplicationDetail> sandDetails = details.stream().filter(detail -> StringUtils.isNotBlank(detail.getDeliveryMethodId())).collect(Collectors.toList());
            List<ReprintCode> reprinting = reprintCodeService.getReprinting(1);

            Map<String, Boolean> reprintingMap = new HashMap<>();
            for (ReprintCode reprintCode : reprinting) {
                String detailId = reprintCode.getDetailId();
                reprintingMap.put(detailId, true);
            }
            for (LabelApplicationDetail sandDetail : sandDetails) {
                String detailId = sandDetail.getId();
                if (reprintingMap.getOrDefault(detailId,false)){
                    throw new RuntimeException("有订单正在重打中，不能发放");
                }
            }

            Map<String, LabelApplicationDetail> oldDetailMap = new HashMap<>();
            for (LabelApplicationDetail oldDetail : oldDetails) {
                Boolean isSend = oldDetail.getIsSend();
                if (Objects.isNull(isSend) || !isSend) {
                    oldDetailMap.put(oldDetail.getId(), oldDetail);
                }
            }


            if (CollectionUtils.isNotEmpty(details)) {
                List<LabelApplicationDetail> updateDetails = new ArrayList<>();
                for (LabelApplicationDetail detail : details) {
                    String detailId = detail.getId();
                    LabelApplicationDetail oldDetail = oldDetailMap.get(detailId);
                    if (!Objects.isNull(oldDetail)) {
                        String deliveryMethodId = detail.getDeliveryMethodId();
                        if (StringUtils.isNotBlank(deliveryMethodId)) {
                            updateDetails.add(new LabelApplicationDetail(oldDetail, detail, true));
                            oldDetailMap.remove(detailId);
                        }
                    }
                }
                if (CollectionUtils.isNotEmpty(updateDetails)) {
                    //修改已经发放的从表商品信息
                    detailService.updateSendBash(updateDetails);

                    //修改标签发放信息
                    List<String> detailIds = updateDetails.stream().map(LabelApplicationDetail::getId).collect(Collectors.toList());
                    List<PrintCode> printCodes = printCodeService.getListByDetailIds(detailIds);
                    if (CollectionUtils.isNotEmpty(printCodes)) {
                        List<String> printCodeIds = printCodes.stream().map(PrintCode::getId).collect(Collectors.toList());
                        printCodeService.updateIsDeliverGoods(printCodeIds, 1);
                    }

                    //修改库存信息
                    Map<String, Long> map = new HashMap<>();
                    for (LabelApplicationDetail updateDetail : updateDetails) {
                        String tagTypeId = updateDetail.getTagTypeId();
                        Long number = updateDetail.getNumber();
                        map.put(tagTypeId, map.getOrDefault(tagTypeId, 0L) + number);
                    }
                    List<TagData> tagDataList = new ArrayList<>();
                    for (Map.Entry<String, Long> entry : map.entrySet()) {
                        String tagTypeId = entry.getKey();
                        Long number = entry.getValue();
                        TagData tagData = new TagData();
                        tagData.setDataType("2");
                        tagData.setTagTypeId(tagTypeId);
                        tagData.setNumber(number);
                        tagData.setStatus("6");
                        tagDataList.add(tagData);
                    }
                    tagDataService.saveOrUpdateBash(null, null, tagDataList, true);

                    //如果没有待发放从表就将主表改为已发放
                    if (CollectionUtils.isEmpty(oldDetailMap)) {
                        labelApplication.setTagApplyStateId("6");
                        this.dao.update(labelApplication);
                    }
                }
            }
        }
        return true;
    }

    @Transactional
    public synchronized Boolean update(LabelApplication entity) {
        String id = entity.getId();
        if (StringUtils.isBlank(id)) throw new RuntimeException("修改失败，没有传id");
        LabelApplication oldLabelApplication = getById(id, false);
        String tagApplyStateId = oldLabelApplication.getTagApplyStateId();
        if (Integer.parseInt(tagApplyStateId) > 1)
            throw new RuntimeException("修改失败，只有待确认和待支付状态才能修改");
        List<LabelApplicationDetail> details = entity.getDetails();

        tagDataService.saveOrUpdateBash(Collections.singletonList(entity), null, null, false);
        detailService.deleteListByLabelApplicationId(id);
        if (CollectionUtils.isEmpty(details)) {
            this.dao.delete(id);
        } else {
            this.dao.update(entity);
            detailService.saveList(details);
        }
        return true;
    }


    public String getMaxOrderNo() {
        return this.dao.getMaxOrderNo();
    }

    @Transactional
    public synchronized Boolean deleteById(String id) {
        LabelApplication entity = getById(id, true);
        if (Objects.isNull(entity)) throw new RuntimeException("删除失败，没有该订单");
        entity.setDetails(new ArrayList<>());
        return update(entity);
    }


    @Transactional
    public synchronized Boolean updateStatus(List<String> labelApplicationIds, String status, boolean isUpdateTagData) {
        if (CollectionUtils.isNotEmpty(labelApplicationIds)) {
            List<LabelApplication> labelApplications = getListByIds(labelApplicationIds);
            List<LabelApplication> labelApplicationList = new ArrayList<>();
            for (LabelApplication labelApplication : labelApplications) {
                String tagApplyStateId = labelApplication.getTagApplyStateId();
                if (!status.equals(tagApplyStateId)) {
                    labelApplication.setTagApplyStateId(status);
                    labelApplicationList.add(labelApplication);
                }
            }
            this.dao.updateListById(labelApplicationList);
            if (isUpdateTagData) {
                tagDataService.saveOrUpdateBash(labelApplicationList, null, null, true);
            }
        }
        return true;
    }

    @Transactional
    public synchronized void updateListById(List<LabelApplication> labelApplicationList) {
        this.dao.updateListById(labelApplicationList);
    }
}
