package com.czg.service.order.print;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import com.czg.account.dto.HandoverRecordDTO;
import com.czg.account.entity.PrintMachine;
import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.print.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.util.*;

/**
 * 博实结-云享印打印机
 * 接口文档 <a href="https://bsj2.yuque.com/bsj/izhmfn/rr8b5g?#ZbE6s">
 *
 * @author Administrator
 */
@Slf4j
@Component
public class YxyPrinter extends PrinterHandler implements PrinterImpl {

    //请求地址
    private static final String URL_STR = "https://ioe.car900.com/v1/openApi/dev/customPrint.json";
    //APPID
    private static final String APP_ID = "ZF544";
    //USERCODE
    private static final String USER_CODE = "ZF544";
    //APPSECRET
    private static final String APP_SECRET = "2022bsjZF544GAH";

    public YxyPrinter() {
        super("云想印");
    }

    private final PrintLabel printLabel = new PrintLabel()
            .setBr("<BR>")
            .setCut("<PCUT>")
            .setOut("OUT")
            .setF(new String[]{"<F>", "</F>"})
            .setL(new String[]{"<L>", "</L>"})
            .setS(new String[]{"<S>", "</S>"})
            .setQr(new String[]{"<QR>", "</QR>"})
            .setCenter(new String[]{"<C>", "</C>"})
            .setCenterBold(new String[]{"<CB>", "</CB>"})
            .setRs("RS")
            .setBold(new String[]{"<BOLD>", "</BOLD>"});


    @Override
    protected void onlyKitchenPrint(Integer isCode, OrderInfo orderInfo, OrderDetail orderDetail, PrintMachine machine) {
        String buildDishPrintData = buildOnlyKitchenPrintData(isCode, getPickupNum(orderInfo), orderDetail);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        if (1 == machine.getVolumeSwitch()) {
            voiceJson = "{\"bizType\":\"2\",\"content\":\"新单来了，请注意查看\"}";
        }
        String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(orderInfo.getId(), machine, "后厨商品单", buildDishPrintData, resp);
    }

    @Override
    public OrderPrintDTO allKitchenPrint(OrderInfo orderInfo, List<OrderDetail> orderDetails, PrintMachine machine) {
        OrderPrintDTO orderPrintDTO = super.allKitchenPrint(orderInfo, orderDetails, machine);
        String buildDishPrintData = buildAllKitchenPrintData(orderPrintDTO, orderDetails);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        if (1 == machine.getVolumeSwitch()) {
            voiceJson = "{\"bizType\":\"2\",\"content\":\"新单来了，请注意查看\"}";
        }
        String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(orderInfo.getId(), machine, "后厨总单", buildDishPrintData, resp);
        return null;
    }

    @Override
    public OrderPrintDTO returnKitchenPrint(String operator, OrderInfo orderInfo, List<OrderDetail> orderDetail, PrintMachine machine) {
        OrderPrintDTO orderPrintDTO = super.returnKitchenPrint(operator, orderInfo, orderDetail, machine);
        String buildDishPrintData = buildAllKitchenPrintData(orderPrintDTO, orderDetail);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        if (1 == machine.getVolumeSwitch()) {
            voiceJson = "{\"bizType\":\"2\",\"content\":\"有客人退菜了，请注意查看\"}";
        }
        String resp = sendPrintRequest(machine.getAddress(), buildDishPrintData, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(orderInfo.getId(), machine, "后厨退菜", buildDishPrintData, resp);
        return null;
    }

    @Override
    public OrderPrintDTO returnOrderPrint(String printTitle, String operator, String refundAmount, String refundReason, String refundType,
                                          OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
        OrderPrintDTO orderPrintDTO = super.returnOrderPrint(printTitle, operator, refundAmount, refundReason, refundType, orderInfo, machine, detailList);
        String data = buildRefundOrderPrintData(orderPrintDTO, detailList);
        sendOrderPrint(data, orderInfo.getId(), machine, printTitle);
        return null;
    }

    @Override
    public OrderPrintDTO guestOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
        OrderPrintDTO orderPrintDTO = super.guestOrderPrint(orderInfo, machine, detailList);
        String data = buildGuestOrderPrintData(orderPrintDTO, detailList);
        sendOrderPrint(data, orderInfo.getId(), machine, "客看单");
        return null;
    }

    @Override
    public OrderPrintDTO preOrderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
        OrderPrintDTO orderPrintDTO = super.preOrderPrint(orderInfo, machine, detailList);
        String data = buildOrderPrintData(orderPrintDTO, detailList);
        sendOrderPrint(data, orderInfo.getId(), machine, "预结算单");
        return null;
    }

    @Override
    public OrderPrintDTO orderPrint(OrderInfo orderInfo, PrintMachine machine, List<OrderDetail> detailList) {
        OrderPrintDTO orderPrintDTO = super.orderPrint(orderInfo, machine, detailList);
        String data = buildOrderPrintData(orderPrintDTO, detailList);
        sendOrderPrint(data, orderInfo.getId(), machine, "结算单");
        return null;
    }

    /**
     * 叫号单打印
     */
    @Override
    protected void callNumPrint(PrintMachine machine, String shopName, CallTablePrintDTO printDTO) {
        String resp = buildCallTicketData(shopName, printDTO);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        if (1 == machine.getVolumeSwitch()) {
            voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
        }
        sendPrintRequest(machine.getAddress(), resp, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
    }


    @Override
    protected void stockPrint(PrintMachine machine, String shopName, StockPrintDTO record) {
        record.setShopName(shopName);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        String data = buildStockData(record);
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(machine, "入库单", data, resp);
    }

    @Override
    protected void dayReportPrint(PrintMachine machine, String shopName, DayReportPrintDTO record) {
        record.setShopName(shopName);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        String data = buildDayReportData(record);
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(machine, "经营日报单", data, resp);
    }

    @Override
    protected void daySettlePrint(PrintMachine machine, String shopName, DaySettlePrintDTO record) {
        record.setShopName(shopName);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        String data = buildDaySettleData(record);
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(machine, "日结单打印", data, resp);
    }

    @Override
    protected void productReportPrint(PrintMachine machine, String shopName, ProductReportPrintDTO record) {
        record.setShopName(shopName);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        String data = buildProductReportData(record);
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(machine, "商品报表单", data, resp);
    }

    @Override
    protected void rechargePrint(PrintMachine machine, String shopName, RechargePrintDTO record) {
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        record.setShopName(shopName);
        String data = buildRechargeData(record);
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(machine, "储值单", data, resp);
    }

    @Override
    protected void stockCheckPrint(PrintMachine machine, String shopName, StockCheckPrintDTO record) {
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        record.setShopName(shopName);
        String data = buildStockCheckData(record);
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(machine, "盘点单", data, resp);
    }


    /**
     * 交班单打印
     */
    @Override
    protected void handoverPrint(PrintMachine machine, String shopName, HandoverRecordDTO record) {
        String string = buildHandoverData(record);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        sendPrintRequest(machine.getAddress(), string, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
    }


    private void sendOrderPrint(String data, Long orderId, PrintMachine machine, String bizType) {
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        if (1 == machine.getVolumeSwitch()) {
            voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一笔新的订单，请及时处理\"}";
            if ("退菜单".equals(bizType)) {
                voiceJson = "{\"bizType\":\"2\",\"content\":\"有客人退菜了，请注意查看\"}";
            }
        }
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(orderId, machine, bizType, data, resp);
    }

    @Override
    public PrintLabel getSignLabelInfo() {
        return printLabel;
    }

    @Override
    public String sendPrintRequest(String address, String metaPrintData, String voiceData, String printNum) {
        log.info("开始请求云享印，请求数据：{}, {}", voiceData, metaPrintData);
        String time = String.valueOf(System.currentTimeMillis());
        String uuid = UUID.randomUUID().toString();
        //参数
        MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>();
        multiValueMap.add("token", getToken(time, uuid));
        multiValueMap.add("devName", address);
        //1:只打印数据 2:只播放信息 3:打印数据并播放信息
        multiValueMap.add("actWay", 3);
        multiValueMap.add("cn", printNum);
        multiValueMap.add("data", metaPrintData);
        multiValueMap.add("voiceJson", voiceData);
        multiValueMap.add("appId", APP_ID);
        multiValueMap.add("timestamp", time);
        multiValueMap.add("requestId", uuid);
        multiValueMap.add("userCode", USER_CODE);
        HttpHeaders header = new HttpHeaders();
        header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multiValueMap, header);
        String httpResponse = restTemplate.postForObject(URL_STR,
                httpEntity, String.class);

        log.info("请求云享印成功，响应数据: {}", httpResponse);
        return httpResponse;
    }


    /**
     * 签名Token
     *
     * @param timestamp 时间戳，13位
     * @param requestId 请求ID，自定义
     * @return token信息
     */
    private static String getToken(String timestamp, String requestId) {
        StringBuilder token = new StringBuilder();
        SortedMap<String, Object> map = new TreeMap<>();
        map.put("appId", APP_ID);
        map.put("timestamp", timestamp);
        map.put("requestId", requestId);
        map.put("userCode", USER_CODE);
        for (Map.Entry<String, Object> next : map.entrySet()) {
            String key = next.getKey();
            Object value = next.getValue();
            token.append(key).append(value);
        }
        return SecureUtil.md5(token + APP_SECRET).toUpperCase();
    }

    /**
     * 检查打印状态
     *
     * @param devName 设备名称，(唯一) 对应配置表中的address字段即（IP地址/打印机编号）
     * @param taskId  打印任务id，用于复查打印状态，云想印=orderId
     */
    public String checkPrintStatus(String devName, String taskId) {
        String time = String.valueOf(System.currentTimeMillis());
        String uuid = UUID.randomUUID().toString();

        Map<String, Object> paramMap = new HashMap<>();

        paramMap.put("devName", devName);
        paramMap.put("orderId", taskId);
        paramMap.put("token", getToken(time, uuid));
        paramMap.put("appId", APP_ID);
        paramMap.put("timestamp", time);
        paramMap.put("requestId", uuid);
        paramMap.put("userCode", USER_CODE);
        String s = HttpUtil.get("https://ioe.car900.com/v1/openApi/dev/findOrder.json", paramMap, 1000 * 5);
        log.info("云想印打印机：{}，任务：{}状态：{}", devName, taskId, s);
        return s;
    }
}
