package com.seer.teach.pay.app.notify.service;

import com.seer.teach.common.enums.pay.PayNotifyTypeEnum;
import com.seer.teach.pay.entity.PayNotifyLogEntity;
import com.seer.teach.pay.entity.PayNotifyTaskEntity;
import com.seer.teach.pay.entity.PayOrderEntity;
import com.seer.teach.pay.entity.RefundOrderEntity;
import com.seer.teach.pay.service.IPayNotifyLogService;
import com.seer.teach.pay.service.IPayNotifyTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;

/**
 * 订单支付通知策略抽象基类
 * 提取通用的通知任务创建和日志记录功能
 */
@Slf4j
public abstract class AbstractOrderPayNotifyHandler implements OrderPayNotifyHandler {

    // 通知状态常量
    private static final int NOTIFY_STATUS_PROCESSING = 1; // 通知中
    private static final int NOTIFY_STATUS_SUCCESS = 1;    // 通知成功
    private static final int NOTIFY_STATUS_FAILED = 0;     // 通知失败

    // 通知时间配置
    private static final int NEXT_NOTIFY_DELAY_MINUTES = 5;

    // 通知次数配置
    private static final int INITIAL_NOTIFY_TIMES = 1;
    private static final int MAX_NOTIFY_TIMES = 5;

    @Autowired
    protected IPayNotifyTaskService payNotifyTaskService;

    @Autowired
    protected IPayNotifyLogService payNotifyLogService;

    /**
     * 创建支付通知任务
     *
     * @param payOrder 支付订单
     * @param type     通知类型
     * @return 通知任务实体
     */
    protected PayNotifyTaskEntity createPayNotifyTask(PayOrderEntity payOrder, Integer type) {
        PayNotifyTaskEntity notifyTask = new PayNotifyTaskEntity();
        notifyTask.setType(type);
        notifyTask.setDataId(payOrder.getId());
        notifyTask.setMerchantOrderSn(payOrder.getMerchantOrderSn());
        notifyTask.setStatus(NOTIFY_STATUS_PROCESSING);
        notifyTask.setNextNotifyTime(LocalDateTime.now().plusMinutes(NEXT_NOTIFY_DELAY_MINUTES));
        notifyTask.setLastExecuteTime(LocalDateTime.now());
        notifyTask.setNotifyTimes(INITIAL_NOTIFY_TIMES);
        notifyTask.setMaxNotifyTimes(MAX_NOTIFY_TIMES);
        return notifyTask;
    }

    /**
     * 创建退款通知任务
     *
     * @param refundOrder 退款订单
     * @param type        通知类型
     * @return 通知任务实体
     */
    protected PayNotifyTaskEntity createRefundNotifyTask(RefundOrderEntity refundOrder, Integer type) {
        PayNotifyTaskEntity notifyTask = new PayNotifyTaskEntity();
        notifyTask.setType(type);
        notifyTask.setDataId(refundOrder.getId());
        notifyTask.setMerchantRefundSn(refundOrder.getMerchantRefundSn());
        notifyTask.setStatus(NOTIFY_STATUS_PROCESSING);
        notifyTask.setNextNotifyTime(LocalDateTime.now().plusMinutes(NEXT_NOTIFY_DELAY_MINUTES));
        notifyTask.setLastExecuteTime(LocalDateTime.now());
        notifyTask.setNotifyTimes(INITIAL_NOTIFY_TIMES);
        notifyTask.setMaxNotifyTimes(MAX_NOTIFY_TIMES);
        return notifyTask;
    }

    /**
     * 创建支付通知日志
     *
     * @param notifyTask   通知任务
     * @param notifyTimes  通知次数
     * @param success      是否成功
     * @param response     响应内容
     * @param duration     耗时(毫秒)
     * @param errorMessage 错误信息
     * @return 通知日志实体
     */
    protected PayNotifyLogEntity createPayNotifyLog(PayNotifyTaskEntity notifyTask, Integer notifyTimes, boolean success,
                                                    String response, long duration, String errorMessage) {
        PayNotifyLogEntity notifyLog = new PayNotifyLogEntity();
        notifyLog.setTaskId(notifyTask.getId());
        notifyLog.setNotifyTimes(notifyTimes);
        // 1 表示通知成功, 0 表示通知失败
        notifyLog.setStatus(success ? NOTIFY_STATUS_SUCCESS : NOTIFY_STATUS_FAILED);
        notifyLog.setResponse(String.format("响应: %s, 耗时: %d ms, 错误信息: %s", response, duration, errorMessage));
        return notifyLog;
    }

    /**
     * 执行通知并记录日志
     *
     * @param notifyTask   通知任务
     * @param notifyType   通知类型
     * @param notifyAction 通知操作
     * @return 操作结果
     */
    protected void executeNotifyWithLog(PayNotifyTaskEntity notifyTask, PayNotifyTypeEnum notifyType, NotifyAction notifyAction) {
        long startTime = System.currentTimeMillis();
        try {
            payNotifyTaskService.save(notifyTask);

            boolean result = notifyAction.execute();
            long endTime = System.currentTimeMillis();

            // 记录成功通知日志
            PayNotifyLogEntity notifyLog = createPayNotifyLog(notifyTask, notifyTask.getNotifyTimes(), true,
                    notifyType.getDescription() + "通知成功", endTime - startTime, null);
            payNotifyLogService.save(notifyLog);

            // 如果通知成功，更新任务状态为成功
            if (result) {
                notifyTask.setStatus(2); // 成功状态
                payNotifyTaskService.updateById(notifyTask);
            }

        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            // 记录失败通知日志
            PayNotifyLogEntity notifyLog = createPayNotifyLog(notifyTask, notifyTask.getNotifyTimes(), false,
                    notifyType.getDescription() + "通知失败", endTime - startTime, e.getMessage());
            payNotifyLogService.save(notifyLog);

            // 更新任务状态为失败
            notifyTask.setStatus(3); // 失败状态
            payNotifyTaskService.updateById(notifyTask);

        }
    }

    /**
     * 通知操作函数式接口
     */
    @FunctionalInterface
    protected interface NotifyAction {
        boolean execute();
    }
}