package com.jwipc.order.controller.pc;

/**
 * <p> </p>
 *
 * @author ZhangJie
 * @version 1.0
 * @since JDK 1.8
 */

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.jwipc.exception.DaoException;
import com.jwipc.order.dto.LabelBarBaseDTO;
import com.jwipc.order.dto.LabelBarImportDTO;
import com.jwipc.order.dto.LabelPrintSettingBaseDTO;
import com.jwipc.order.entity.PurchaseOrderDetail;
import com.jwipc.order.logic.LabelPrintSettingLogic;
import com.jwipc.order.model.query.LabelPrintSettingQuery;
import com.jwipc.order.model.query.LabelQuery;
import com.jwipc.order.service.IPurchaseOrderDetailService;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.util.EasyExcelUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.jwipc.order.constant.ModuleConst.MODULE_ROOT;

/**
 * <p> 标签打印相关接口</p>
 *
 * @author ZhangJie
 * @version 1.0
 * @since JDK 1.8
 */
@RestController
@RequiredArgsConstructor
@RequestMapping(MODULE_ROOT + "/barcodePrinter/rest")
@Slf4j
public class BarcodePrinterRestController {
    private final LabelPrintSettingLogic labelPrintSettingLogic;
    private final IPurchaseOrderDetailService purchaseOrderDetailService;
    private final StringRedisTemplate redisTemplate;
    @GetMapping("list")
    public PageView list(LabelPrintSettingQuery query) {
        return labelPrintSettingLogic.list(query);
    }

    @GetMapping("getPrintData")
    public ResponseEntity getPrintData(Long id, @RequestParam(required = false, defaultValue = "0") Integer isPrint) {
        return ResponseEntity.ok(labelPrintSettingLogic.getLabelBars(id, isPrint));
    }

    @GetMapping("getPrintDataByIds")
    public ResponseEntity getPrintDataByIds(String ids,
                                            @RequestParam(required = false, defaultValue = "0") Integer isPrint)
    {
        return ResponseEntity.ok(labelPrintSettingLogic.getLabelBars(ids, isPrint));
    }

    @PostMapping("rePush")
    public ResponseEntity rePush(Long id) {
        final String s = labelPrintSettingLogic.rePush(id);
        if (StrUtil.isNotEmpty(s)) {
            throw new DaoException(s);
        }
        return ResponseEntity.ok().build();
    }


    @PostMapping("rePushBatch")
    public ResponseEntity rePushByBatch(String ids) {
        final List<String> split = StrUtil.split(ids, StringPool.COMMA);
        Set<String> msg = Sets.newHashSet();
        for (String s : split) {
            final String tmp = labelPrintSettingLogic.rePush(Long.valueOf(s));
            if (StrUtil.isNotEmpty(tmp)) {
                msg.add(tmp);
            }
        }
        if (CollUtil.isNotEmpty(msg)) {
            throw new DaoException(msg.stream().collect(Collectors.joining("</br>")));
        }
        return ResponseEntity.ok().build();
    }

    @PostMapping("print")
    public ResponseEntity print(@RequestBody LabelPrintSettingBaseDTO printSettingBaseDTO) {
        log.info("界面打印参数:{}", printSettingBaseDTO);
        log.info("界面打印开始");
        final String supplierCode = printSettingBaseDTO.getSupplierCode();
        final String materialCode = printSettingBaseDTO.getMaterialCode();
        final String po = printSettingBaseDTO.getPurchaseOrderCode();
        if (po.startsWith("KG") || po.startsWith("YP")) {
        } else {
            final PurchaseOrderDetail orderDetail = purchaseOrderDetailService.getOne(
                    new LambdaQueryWrapper<PurchaseOrderDetail>()
                            .eq(PurchaseOrderDetail::getOrderCode, po)
                            .eq(PurchaseOrderDetail::getSupplierErpCode, supplierCode)
                            .eq(PurchaseOrderDetail::getMaterialCode, materialCode), false);
            if (Objects.isNull(orderDetail)) {
                throw new DaoException("订单信息不存在");
            }
        }
        //增加重复算提交校验
        String lockKey = "label:print:" + po + ":" + materialCode + ":" + supplierCode;
        if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS)) {
            throw new DaoException("正在生成标签，请稍后重试");
        }

        List<LabelBarBaseDTO> baseDTOS = labelPrintSettingLogic.print_new(printSettingBaseDTO, LoginUtil.getUserId());
        log.info("界面打印结束");
        // 6) 事务外：推送MES（失败不影响返回，不回滚已生成条码）
        if (CollUtil.isNotEmpty(baseDTOS)) {
            Long settingId = baseDTOS.get(0).getSettingId(); // 获取本次生成的主表ID
            try {
                // 调用 rePush，此时 print 的事务已经提交，数据可见，无锁冲突
                labelPrintSettingLogic.rePush(settingId);
            } catch (Exception e) {
                log.error("MES推送失败，但标签已生成，SettingId: {}", settingId, e);
                // 根据业务需求，这里可以选择是否抛出异常或者仅记录日志
                // 如果需要告知前端推送失败，可以在这里处理
            }
        }
        redisTemplate.delete(lockKey);
        return ResponseEntity.ok(baseDTOS);
    }

    @GetMapping("labelList")
    public PageView labelList(LabelQuery query) {
        return labelPrintSettingLogic.labelList(query);
    }

    /**
     * 标签关系导入
     *
     * @param file
     * @return
     */
    @PostMapping("/import")
    public ResponseEntity importData(@RequestPart("file") MultipartFile file) {
        List<LabelBarImportDTO> cachedDataList = Lists.newArrayList();
        try {
            EasyExcel.read(file.getInputStream(), LabelBarImportDTO.class,
                    new ReadListener<LabelBarImportDTO>() {
                        @Override
                        public void invoke(LabelBarImportDTO data, AnalysisContext context) {
                            final String out = data.getOut();

                            final String validate1 = validate(out);
                            if (StrUtil.isNotEmpty(validate1)) {
                                throw new DaoException(validate1);
                            }
                            final String inner = data.getInner();
                            final String validate = validate(inner);
                            if (StrUtil.isNotEmpty(validate)) {
                                throw new DaoException(validate);
                            }
                            cachedDataList.add(data);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        labelPrintSettingLogic.importLabel(cachedDataList);
        return ResponseEntity.ok(StringPool.EMPTY);
    }

    @PostMapping("remove")
    public ResponseEntity remove(String ids) {
        labelPrintSettingLogic.remove(ids);
        return ResponseEntity.ok().build();
    }

    @PostMapping("removeByBatch")
    public ResponseEntity removeByBatch(Long id) {
        labelPrintSettingLogic.removeByBatch(id);
        return ResponseEntity.ok().build();
    }

    @PostMapping("rePushByBatch")
    public ResponseEntity rePushByBatch(Long id) {
        labelPrintSettingLogic.rePushByBatch(id);
        return ResponseEntity.ok().build();
    }


    public static String validate(String printContent) {
        // 定义正则表达式
        Pattern reg = Pattern.compile(".*[\u4e00-\u9fa5]+.*$");
        Pattern barcodeReg = Pattern.compile("[BPR]");

        String msg = "";

        // 按照 " {" 分割字符串
        String[] parts = printContent.split("\\s*\\{\\s*");

        if (parts.length - 1 == 12) {
            String CPN = parts[0].trim();
            String QTY = parts[1].trim();
            String DC = parts[4].trim();
            String BarcodeNo = parts[8].trim();
            String Manufacture = parts[10].trim();

            // 汉字检测
            Matcher matcher = reg.matcher(printContent);
            if (matcher.find()) {
                msg = "二维码中不能含有汉字!!! 请确认";
            }
            // 数量检测
            else if (!QTY.matches("^[1-9]\\d*$")) {
                msg = "二维码中数量不正确!!! 请确认";
            }
            // 制造商不能为空
            else if (Manufacture.isEmpty()) {
                msg = "制造商不能为空!!! 请确认";
            }
            // 二维码流水号检测
            else if (!barcodeReg.matcher(BarcodeNo).find()) {
                msg = "二维码中流水号不正确!!! 请确认";
            }
            // DC周期长度检测
            else if (DC.length() != 4) {
                msg = "DC周期不正确!!! 规则：年份+周数（2130）";
            }
        } else {
            msg = "二维码格式不正确！！！ 请确认";
        }

        return msg;
    }

    @PostMapping("exportPDF")
    public ResponseEntity exportPDF(@RequestBody Map<String, String> data, HttpServletResponse response) {
        labelPrintSettingLogic.exportPDF(data.get("data"), response);
        return ResponseEntity.ok("OK");
    }

    @PostMapping("updatePrintSize")
    public ResponseEntity updatePrintSize (Long id) {
        labelPrintSettingLogic.updatePrintSize(id);
        return ResponseEntity.ok("OK");
    }

    /**
     * 列表导出
     *
     * @param exportFiled 导出的列信息
     * @param queryStr 查询条件
     */
    @PostMapping("/export")
    public void export(HttpServletResponse response, String exportFiled, String queryStr) throws IOException {
        // 查询数据列表，直接调用列表的查询，无需特殊改动
        final List<LabelBarBaseDTO> exportData = labelPrintSettingLogic.getExportData(JSON.parseObject(queryStr, LabelQuery.class));
        //动态导出工具类，只需要修改导出excel名称
        EasyExcelUtils.trendsModelWrite(response,"物料条码" + DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN),"sheet", exportData, exportFiled);
    }
}
