package com.czg.service.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapProxy;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.czg.account.entity.PrintMachine;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.order.entity.PrintMachineLog;
import com.czg.order.service.PrintMachineLogService;
import com.czg.service.order.mapper.PrintMachineLogMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 店铺小票打印记录ServiceImpl
 *
 * @author tankaikai
 * @since 2024-10-8 17:10
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMapper, PrintMachineLog> implements PrintMachineLogService{
    //请求地址
    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 static final String URL = "http://api.feieyun.cn/Api/Open/";//不需要修改

    public static final String USER = "chaozhanggui2022@163.com";//*必填*：账号名
    public static final String UKEY = "UfWkhXxSkeSSscsU";//*必填*: 飞鹅云后台注册账号后生成的UKEY 【备注：这不是填打印机的KEY】
    public static final String SN = "960238952";//*必填*：打印机编号，必须要在管理后台里添加打印机或调用API接口添加之后，才能调用API
    /**
     * 获取TOKEN值
     *
     * @param timestamp 时间戳，13位
     * @param requestId 请求ID，自定义
     * @return
     */
    private static Map<String, String> getToken(String timestamp, String requestId) {
        StringBuilder token = new StringBuilder();
        StringBuilder encode = 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);
            encode.append(key).append("=").append(value).append("&");
        }
        System.out.println("token" + token);
        Map<String, String> finalMap = new HashMap<>();
        finalMap.put("ENCODE", encode.toString());
        System.out.println("+++++++++++++++" + token + APP_SECRET);
        finalMap.put("TOKEN", SecureUtil.md5(token + APP_SECRET).toUpperCase());
        return finalMap;
    }
    /**
     * 检查打印状态
     *
     * @param devName 设备名称，(唯一) 对应配置表中的address字段即（IP地址/打印机编号）
     * @param taskId  打印任务id，用于复查打印状态，云想印=orderId
     * @return
     */
    public static String checkPrintStatus(String devName, String taskId) {
        String time = String.valueOf(System.currentTimeMillis());
        String uuid = UUID.randomUUID().toString();

        Map<String, String> param = getToken(time, uuid);
        String token = param.get("TOKEN");
        Map<String, Object> paramMap = new HashMap<>();

        paramMap.put("devName", devName);
        paramMap.put("orderId", taskId);
        paramMap.put("token", token);
        paramMap.put("appId", APP_ID);
        paramMap.put("timestamp", time);
        paramMap.put("requestId", uuid);
        paramMap.put("userCode", USER_CODE);

        return HttpUtil.get("https://ioe.car900.com/v1/openApi/dev/findOrder.json", paramMap, 1000 * 5);
    }
    private static String signature(String USER, String UKEY, String STIME) {
        return DigestUtils.sha1Hex(USER + UKEY + STIME);
    }
    /**
     * 检查飞鹅打印机打印任务是否已打印
     *
     * @param printOrderId 打印订单编号
     * @return null-未知错误，true-已打印，false-未打印
     */
    public static Boolean checkFPrintStatus(String printOrderId) {
        String STIME = String.valueOf(System.currentTimeMillis() / 1000);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("user", USER);
        paramMap.put("stime", STIME);
        paramMap.put("sig", signature(USER, UKEY, STIME));
        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));
            ret = json.getBool("data");
        } catch (Exception e) {
            ret = null;
        }
        return ret;
    }
    /**
     * 检查飞鹅打印机是否在线
     *
     * @param sn 设备编号
     * @return 在线，工作状态正常。/离线。/未知错误
     */
    public static String checkOnline(String sn) {
        String STIME = String.valueOf(System.currentTimeMillis() / 1000);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("user", USER);
        paramMap.put("stime", STIME);
        paramMap.put("sig", signature(USER, UKEY, STIME));
        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));
            msg = json.getStr("data");
        } catch (Exception e) {
            msg = "未知错误";
        }
        return msg;
    }
    /**
     * 保存打印记录
     *
     * @param config       打印机配置
     * @param bizType      业务类型
     * @param printContent 打印内容
     * @param respJson     打印机响应结果
     */
    @Async
    public void save(PrintMachine config, String bizType, String printContent, Object respJson) {
        if (config == null) {
            return;
        }
        PrintMachineLog entity = new PrintMachineLog();
        BeanUtil.copyProperties(config, entity, "id");
        int failFlag = 0;
        String respCode = "0";
        String respMsg = "打印中";

        Map<Integer, String> yxxStatusMap = MapUtil.builder(0, "离线(设备上线后自动补打)").put(1, "在线").put(2, "获取失败").put(3, "未激活").put(4, "设备已禁用").build();
        // 云想印
        if ("云享印".equals(config.getContentType())) {
            cn.hutool.json.JSONObject resp = JSONUtil.parseObj(respJson);
            int code = resp.getInt("code");
            cn.hutool.json.JSONObject data = resp.getJSONObject("data").getJSONObject("data");
            //设备状态，0: 离线, 1: 在线, 2: 获取失败, 3:未激活, 4:设备已禁用
            int status = data.getInt("status");
            if (code != 0) {
                failFlag = 1;
                respCode = code + "";
                respMsg = resp.getStr("msg");
            } else if (status != 1) {
                failFlag = 1;
                respCode = code + "";

                respMsg = status + "_" + yxxStatusMap.get(status);
            }
            if (code == 0) {
                String taskId = resp.getJSONObject("data").getStr("orderId");
                entity.setTaskId(taskId);
            }
            // 飞鹅云打印机暂时没有适配，先return不做打印记录
        } else if ("飞鹅".equals(config.getContentType())) {
            cn.hutool.json.JSONObject resp = JSONUtil.parseObj(respJson);
            int ret = resp.getInt("ret");
            if (ret != 0) {
                failFlag = 1;
                respCode = ret + "";
                respMsg = resp.getStr("msg");
            } else {
                String printOrderId = resp.getStr("data");
                entity.setTaskId(printOrderId);
            }
        } else {
            // 其他打印机暂时没有适配，先return不做打印记录
            return;
        }
        entity.setBizType(bizType);
//        entity.setCreateUserId(config.getCurrentUserId());
//        entity.setCreateUserName(config.getCurrentUserName());
//        if (StrUtil.isNotBlank(config.getCurrentUserNickName())) {
//            entity.setCreateUserName(StrUtil.concat(true, config.getCurrentUserNickName(), " | ", config.getCurrentUserName()));
//        }
        entity.setPrintContent(printContent);
        entity.setCreateTime(DateUtil.date().toLocalDateTime());
        if (failFlag == 0) {
            entity.setPrintTime(entity.getCreateTime());
        }
        entity.setFailFlag(failFlag);
        entity.setRespCode(respCode);
        entity.setRespMsg(respMsg);
        super.save(entity);

        // 云想印
        if ("云享印".equals(config.getContentType())) {
            // 延迟3ms，复查打印状态 (用户可以根据设备信息查询到当前设备的在线情况（注：该接口只能提供参考，设备的离线状态是在设备离线3分钟后才会生效）)
            ThreadUtil.safeSleep(1000 * 5);
            String jsonStr = checkPrintStatus(config.getAddress(), entity.getTaskId());
            cn.hutool.json.JSONObject resp = JSONUtil.parseObj(jsonStr);
            int code = resp.getInt("code");
            if (code == 0) {
                cn.hutool.json.JSONObject data = resp.getJSONObject("data");
                boolean status = data.containsKey("status");
                if (!status) {
                    return;
                }
                boolean success = data.getBool("status", false);
                if (entity.getFailFlag() == 0 && success) {
                    entity.setFailFlag(0);
                    entity.setRespMsg("打印成功");
                    entity.setPrintTime(entity.getCreateTime());
                } else if (entity.getFailFlag() == 1 && success) {
                    entity.setFailFlag(0);
                    entity.setPrintTime(DateUtil.date().toLocalDateTime());
                    entity.setRespMsg("打印成功");
                    // 如果设备在线 and 休眠5秒后查询结果是未打印，即视为设备已离线，云端3分钟后才会同步到离线信息
                } else if (entity.getFailFlag() == 0 && !success) {
                    entity.setFailFlag(1);
                    entity.setPrintTime(null);
                    entity.setRespMsg("0_离线(设备上线后自动补打)");
                } else {
                    entity.setFailFlag(1);
                    entity.setPrintTime(null);
                    entity.setRespMsg(StrUtil.concat(true, "打印失败，", "_", entity.getRespMsg()));
                }
                super.updateById(entity);
            }
            // 飞鹅云打印机
        } else if ("飞鹅".equals(config.getContentType())) {
            ThreadUtil.safeSleep(1000 * 5);
            Boolean success = checkFPrintStatus(entity.getTaskId());
            if (success == null) {
                entity.setFailFlag(1);
                entity.setRespMsg("打印失败，未知错误");
            } else if (success) {
                entity.setFailFlag(0);
                entity.setPrintTime(DateUtil.date().toLocalDateTime());
                entity.setRespMsg("打印成功");
            } else {
                String msg = checkOnline(entity.getAddress());
                if (msg.indexOf("在线，工作状态正常") > 0) {
                    entity.setFailFlag(0);
                    entity.setPrintTime(DateUtil.date().toLocalDateTime());
                    entity.setRespMsg("打印成功");
                } else {
                    entity.setFailFlag(1);
                    entity.setPrintTime(null);
                    entity.setRespMsg(StrUtil.concat(true, "打印失败，", "_", msg));
                }
            }
            super.updateById(entity);
        }
    }

}
