package com.czg.service.order.print;

import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
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.apache.commons.codec.digest.DigestUtils;
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.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 * 接口文档  <a href="https://help.feieyun.com/home/doc/zh;nav=1-1">
 */
@Component
@Slf4j
public class FeiPrinter extends PrinterHandler implements PrinterImpl {

    // API 地址
    private static final String URL = "http://api.feieyun.cn/Api/Open/";

    // 飞鹅云 API 账号
    private static final String USER = "chaozhanggui2022@163.com";
    private static final String UKEY = "UfWkhXxSkeSSscsU";

    public FeiPrinter() {
        super("飞鹅");
    }

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

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

    @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 queue) {
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        if (1 == machine.getVolumeSwitch()) {
            voiceJson = "{\"bizType\":\"2\",\"content\":\"您有一条新的排号记录\"}";
        }
        String data = buildCallTicketData(shopName, queue);
        String resp = sendPrintRequest(machine.getAddress(), data, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
        printMachineLogService.save(machine, "叫号单", data, resp);
    }

    @Override
    protected void stockPrint(PrintMachine machine, String shopName, StockPrintDTO record) {
        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, "IN".equals(record.getType()) ? "入库单" : "出库单", 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) {
        record.setShopName(shopName);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        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) {
        record.setShopName(shopName);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        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) {
        record.setShopName(shopName);
        String string = buildHandoverData(record);
        String voiceJson = "{\"bizType\":\"2\",\"content\":\"\"}";
        sendPrintRequest(machine.getAddress(), string, voiceJson, machine.getPrintNum() == null ? "1" : machine.getPrintNum().toString());
    }

    /**
     * 生成签名
     */
    private static String signature(String timeStamp) {
        return DigestUtils.sha1Hex(FeiPrinter.USER + FeiPrinter.UKEY + timeStamp);
    }

    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 String sendPrintRequest(String address, String metaPrintData, String voiceData, String printerNum) {
        log.info("飞蛾打印机开始发送打印请求, 设备地址: {}, 元数据: {}", address, metaPrintData);
        String time = String.valueOf(System.currentTimeMillis() / 1000);
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("user", USER);
        formData.add("stime", time);
        formData.add("sig", signature(time));
        formData.add("apiname", "Open_printMsg");
        formData.add("sn", address);
        formData.add("content", metaPrintData);
        formData.add("times", printerNum == null ? "1" : printerNum);

        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

            HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(formData, headers);

            String result = restTemplate.postForObject(URL, requestEntity, String.class);
            log.info("飞鹅打印结果: {}", result);
            return result;
        } catch (Exception e) {
            log.error("打印请求失败: {}", e.getMessage());
            throw new RuntimeException("飞蛾打印请求失败", e);
        }
    }

    /**
     * 检查飞鹅打印机 打印任务是否已打印
     *
     * @param printOrderId 打印订单编号
     * @return null-未知错误，true-已打印，false-未打印
     */
    public Boolean checkPrintStatus(String printOrderId) {
        String time = String.valueOf(System.currentTimeMillis() / 1000);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("user", USER);
        paramMap.put("stime", time);
        paramMap.put("sig", signature(time));
        paramMap.put("apiname", "Open_queryOrderState");
        paramMap.put("orderid", printOrderId);
        Boolean ret;
        try {
            String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
            //成功 {"msg":"ok","ret":0,"data":true,"serverExecutedTime":4}
            //失败 {"msg":"ok","ret":0,"data":false,"serverExecutedTime":4}
            JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
            log.info("飞鹅打印机 打印任务状态响应: {}", json);
            ret = json.getBool("data");
        } catch (Exception e) {
            ret = null;
        }
        return ret;
    }

    /**
     * 检查飞鹅打印机是否在线
     *
     * @param sn 设备编号
     * @return 在线，工作状态正常。/离线。/未知错误
     */
    public String checkOnline(String sn) {
        String time = String.valueOf(System.currentTimeMillis() / 1000);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("user", USER);
        paramMap.put("stime", time);
        paramMap.put("sig", signature(time));
        paramMap.put("apiname", "Open_queryPrinterStatus");
        paramMap.put("sn", sn);
        String msg;
        try {
            String resp = HttpUtil.post(URL, paramMap, 1000 * 5);
            //成功 开机 {"msg":"ok","ret":0,"data":"在线，工作状态正常。","serverExecutedTime":4}
            //成功 离线 {"msg":"ok","ret":0,"data":"离线。","serverExecutedTime":7}
            JSONObject json = JSONUtil.parseObj(UnicodeUtil.toString(resp));
            log.info("飞鹅打印机状态响应：{}", json);
            msg = json.getStr("data");
        } catch (Exception e) {
            msg = "未知错误";
        }
        return msg;
    }
}
