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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.PrintMachine;
import com.czg.order.entity.PrintMachineLog;
import com.czg.order.service.PrintMachineLogService;
import com.czg.service.order.mapper.PrintMachineLogMapper;
import com.czg.service.order.print.FeiPrinter;
import com.czg.service.order.print.YxyPrinter;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 店铺小票打印记录ServiceImpl
 *
 * @author tankaikai
 * @since 2024-10-8 17:10
 */
@Slf4j
@Service
public class PrintMachineLogServiceImpl extends ServiceImpl<PrintMachineLogMapper, PrintMachineLog> implements PrintMachineLogService {

    @Lazy
    @Resource
    private YxyPrinter yxyPrinter;
    @Lazy
    @Resource
    private FeiPrinter feiPrinter;

    Map<Integer, String> yxxStatusMap = Map.of(
            0, "离线(设备上线后自动补打)",
            1, "在线",
            2, "获取失败",
            3, "未激活",
            4, "设备已禁用");

    @Async
    @Override
    public void save(PrintMachine config, String bizType, String printContent, String respJson) {
        if (config == null) {
            return;
        }
        save(null, config, bizType, printContent, respJson);
    }

    /**
     * 保存打印记录
     *
     * @param orderId      订单Id
     * @param config       打印机配置
     * @param bizType      业务类型
     * @param printContent 打印内容
     * @param respJson     打印机响应结果
     */
    @Async
    @Override
    public void save(Long orderId, PrintMachine config, String bizType, String printContent, String respJson) {
        if (config == null) {
            return;
        }
        PrintMachineLog entity = new PrintMachineLog();
        BeanUtil.copyProperties(config, entity, "id");
        int failFlag = 0;
        String respCode = "0";
        String respMsg = "打印中";
        JSONObject resp = JSONObject.parseObject(respJson);
        // 云想印
        if ("云想印".equals(config.getBrand())) {
            int code = resp.getIntValue("code");
            JSONObject respData = resp.getJSONObject("data");
            JSONObject data = respData.getJSONObject("data");
            //设备状态，0: 离线, 1: 在线, 2: 获取失败, 3:未激活, 4:设备已禁用
            int status = data.getIntValue("status");
            if (code != 0) {
                failFlag = 1;
                respCode = code + "";
                respMsg = resp.getString("msg");
            } else if (status != 1) {
                failFlag = 1;
                respCode = code + "";
                respMsg = status + "_" + yxxStatusMap.get(status);
            }
            if (code == 0) {
                entity.setTaskId(respData.getString("orderId"));
            }
            // 飞鹅云打印机暂时没有适配，先return不做打印记录
        } else if ("飞鹅".equals(config.getBrand())) {
            int ret = resp.getIntValue("ret");
            if (ret != 0) {
                failFlag = 1;
                respCode = ret + "";
                respMsg = resp.getString("msg");
            } else {
                entity.setTaskId(resp.getString("data"));
            }
        } else {
            // 其他打印机暂时没有适配，先return不做打印记录
            return;
        }
        entity.setPrintContentType(bizType);
        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);
        ThreadUtil.execAsync(() -> checkPrintStatus(config, entity));
    }

    /**
     * 类级别成员变量：基于虚拟线程的固定大小（5）定时线程池
     * // Java 21+ 虚拟线程工厂，支持命名
     */
    private final ScheduledExecutorService virtualThreadScheduler = Executors.newScheduledThreadPool(
            5,
            Thread.ofVirtual().name("print-query-vt-", 0).factory()
    );

    /**
     * 打印机状态查询（解决 retryFuture 爆红问题 + 虚拟线程 + 轮询重试）
     *
     * @param config 打印机配置
     * @param entity 打印日志实体
     */
    public void checkPrintStatus(PrintMachine config, PrintMachineLog entity) {
        // 最大重试次数
        int maxRetryTimes = 5;
        AtomicInteger executedTimes = new AtomicInteger(0);

        // 原子引用包装ScheduledFuture，用于后续取消轮询
        AtomicReference<ScheduledFuture<?>> retryFutureRef = new AtomicReference<>();

        // 核心查询任务（修正后，逻辑内聚）
        Runnable printQueryTask = () -> {
            int currentTimes = executedTimes.incrementAndGet();
            boolean isPrintSuccess = false;
            boolean isLastTask = false;

            try {
                // 1. 云想印打印机状态查询
                if ("云想印".equals(config.getBrand())) {
                    String jsonStr = yxyPrinter.checkPrintStatus(config.getAddress(), entity.getTaskId());
                    log.info("云想印打印状态查询结果（第{}次，虚拟线程：{}）：{}",
                            currentTimes, Thread.currentThread().getName(), jsonStr);
                    JSONObject resp = JSONObject.parseObject(jsonStr);
                    int code = resp.getIntValue("code");
                    if (code == 0) {
                        JSONObject data = resp.getJSONObject("data");
                        if (data.containsKey("status")) {
                            isPrintSuccess = data.getBooleanValue("status", false);
                            updatePrintLogEntity(entity, isPrintSuccess);
                        }
                    }
                }
                // 2. 飞鹅云打印机状态查询
                else if ("飞鹅".equals(config.getBrand())) {
                    Boolean success = feiPrinter.checkPrintStatus(entity.getTaskId());
                    if (success == null) {
                        entity.setFailFlag(1);
                        entity.setRespMsg("打印失败，未知错误");
                        entity.setPrintTime(null);
                    } else if (success) {
                        isPrintSuccess = true;
                        updatePrintLogEntity(entity, true);
                    } else {
                        String msg = feiPrinter.checkOnline(entity.getAddress());
                        if (msg.indexOf("在线，工作状态正常") > 0) {
                            isPrintSuccess = true;
                            updatePrintLogEntity(entity, true);
                        } else {
                            isPrintSuccess = false;
                            entity.setFailFlag(1);
                            entity.setPrintTime(null);
                            entity.setRespMsg(StrUtil.concat(true, "打印失败，", "_", msg));
                        }
                    }
                } else {
                    log.info("打印类型为其他类型，终止打印状态查询轮询任务");
                    ScheduledFuture<?> future = retryFutureRef.get();
                    if (future != null && !future.isCancelled()) {
                        boolean cancelSuccess = future.cancel(false); // 取消后续轮询（不中断当前任务）
                        log.info("其他打印类型，取消轮询任务：{}", cancelSuccess ? "成功" : "失败");
                    }
                }

                // 3. 打印成功：取消后续轮询任务
                if (isPrintSuccess) {
                    isLastTask = true;
                    ScheduledFuture<?> future = retryFutureRef.get();
                    if (future != null && !future.isCancelled()) {
                        future.cancel(false); // 不中断当前任务，仅取消后续任务
                    }
                    return;
                }

                // 4. 达到最大重试次数：取消后续轮询任务
                if (currentTimes >= maxRetryTimes) {
                    isLastTask = true;
                    ScheduledFuture<?> future = retryFutureRef.get();
                    if (future != null && !future.isCancelled()) {
                        future.cancel(false);
                    }
                }

            } catch (Exception e) {
                log.error("第{}次打印机状态查询异常（虚拟线程：{}）",
                        currentTimes, Thread.currentThread().getName(), e);
                // 异常时达到最大重试次数，同样取消任务
                if (currentTimes >= maxRetryTimes) {
                    ScheduledFuture<?> future = retryFutureRef.get();
                    if (future != null && !future.isCancelled()) {
                        boolean cancelSuccess = future.cancel(false);
                        log.info("查询异常且达到最大重试次数，取消轮询任务：{}", cancelSuccess ? "成功" : "失败");
                    }
                }
            } finally {
                //仅当是最后一次任务时，才执行更新操作
                if (isLastTask) {
                    super.updateById(entity);
                }
            }
        };

        // 修正：统一使用scheduleAtFixedRate，避免任务重复执行
        // 首次延迟10秒执行，后续每隔30秒执行一次（符合原逻辑的首次查询延迟，后续轮询间隔）
        ScheduledFuture<?> retryFuture = virtualThreadScheduler.scheduleAtFixedRate(
                printQueryTask,
                10,
                30,
                TimeUnit.SECONDS
        );

        // 修正：先赋值AtomicReference，再让任务可能执行，避免线程安全隐患
        retryFutureRef.set(retryFuture);
        // 修正：关闭钩子仅注册一次（通过静态代码块或类初始化时注册，避免重复注册）
        registerShutdownHookOnce();
    }

    /**
     * 统一更新打印日志实体
     *
     * @param entity         打印日志实体
     * @param isPrintSuccess 是否打印成功
     */
    private void updatePrintLogEntity(PrintMachineLog entity, boolean isPrintSuccess) {
        if (isPrintSuccess) {
            entity.setFailFlag(0);
            entity.setRespMsg("打印成功");
            entity.setPrintTime(entity.getFailFlag() == 0 ? entity.getCreateTime() : DateUtil.date().toLocalDateTime());
        } else {
            entity.setFailFlag(1);
            entity.setPrintTime(null);
            if (entity.getFailFlag() == 0) {
                entity.setRespMsg("0_离线(设备上线后自动补打)");
            } else {
                entity.setRespMsg(entity.getRespMsg());
            }
        }
    }

    // 静态标识，确保关闭钩子仅注册一次
    private static volatile boolean shutdownHookRegistered = false;
    // 锁对象，保证线程安全
    private static final Object HOOK_LOCK = new Object();

    /**
     * 统一注册JVM关闭钩子（仅执行一次）
     */
    private void registerShutdownHookOnce() {
        if (!shutdownHookRegistered) {
            synchronized (HOOK_LOCK) {
                // 双重校验锁，避免多线程下重复注册
                if (!shutdownHookRegistered) {
                    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
                        if (virtualThreadScheduler != null && !virtualThreadScheduler.isShutdown()) {
                            virtualThreadScheduler.shutdown();
                            try {
                                if (!virtualThreadScheduler.awaitTermination(10, TimeUnit.SECONDS)) {
                                    log.warn("虚拟线程调度器10秒内未关闭，强制关闭...");
                                    virtualThreadScheduler.shutdownNow();
                                }
                            } catch (InterruptedException e) {
                                log.error("等待虚拟线程调度器终止时被中断，强制关闭", e);
                                virtualThreadScheduler.shutdownNow();
                                Thread.currentThread().interrupt(); // 保留中断状态
                            }
                        }
                    }, "PrinterScheduler-ShutdownHook"));
                    shutdownHookRegistered = true;
                }
            }
        }
    }
}
