package com.njzscloud.common.sichen.support;

import cn.hutool.core.util.IdUtil;
import com.njzscloud.common.core.thread.ThreadContext;
import com.njzscloud.common.sichen.contant.ScheduleType;
import com.njzscloud.common.sichen.contant.TaskLogLevel;
import com.njzscloud.common.sichen.contant.TaskStatus;
import com.njzscloud.common.sichen.service.TaskScheduleRecodeService;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;

@Slf4j
@Getter
@Setter
@Accessors(chain = true)
public class TaskHandle implements Runnable {
    /**
     * 任务 Id
     */
    private volatile long taskId;
    /**
     * 调度 Id
     */
    private volatile long scheduleId;
    /**
     * 任务名称
     */
    private volatile String taskName;
    /**
     * 备注
     */
    private volatile String memo;
    /**
     * 调度方式; 字典代码：schedule_type
     */
    private volatile ScheduleType scheduleType;
    /**
     * 调度配置; 手动时为空，固定周期时单位为秒
     */
    private volatile String scheduleConf;
    /**
     * 执行函数名
     */
    private volatile String fn;
    /**
     * 任务函数句柄
     */
    private FnHandle fnHandle;
    /**
     * 任务状态
     */
    private volatile TaskStatus taskStatus;
    /**
     * 调度时间
     */
    private volatile LocalDateTime scheduleTime;
    /**
     * 开始时间
     */
    private volatile LocalDateTime startTime;
    /**
     * 结束时间
     */
    private volatile LocalDateTime endTime;
    /**
     * 本次调度是否为手动触发
     */
    private volatile boolean manually;

    /**
     * 日志等级
     */
    private TaskLogLevel logLevel;
    /**
     * 是否为内内置任务
     */
    private boolean builtin;
    private TaskScheduleRecodeService taskScheduleRecodeService;

    public TaskHandle(TaskScheduleRecodeService taskScheduleRecodeService, boolean manually, TaskInfo taskInfo) {
        this.taskId = taskInfo.getId();
        this.scheduleId = IdUtil.getSnowflakeNextId();
        this.memo = taskInfo.getMemo();
        this.taskName = taskInfo.getTaskName();
        this.taskStatus = TaskStatus.Waiting;
        this.fn = taskInfo.getFn();
        this.fnHandle = TaskStore.getFn(this.fn);
        this.scheduleType = taskInfo.getScheduleType();
        this.scheduleConf = taskInfo.getScheduleConf();
        this.scheduleTime = LocalDateTime.now();
        this.taskScheduleRecodeService = taskScheduleRecodeService;
        this.manually = manually;
        this.logLevel = taskInfo.getLogLevel();
        this.builtin = taskInfo.isBuiltin();
        taskScheduleRecodeService.schedule(this);
        this.logInfo("开始调度");
    }

    public static TaskHandle getTaskHandle() {
        return ThreadContext.get("CURRENT_TASK");
    }

    public static void debug(String msg, Object... params) {
        getTaskHandle().logDebug(msg, params);
    }

    public static void info(String msg, Object... params) {
        getTaskHandle().logInfo(msg, params);
    }

    public static void warn(String msg, Object... params) {
        getTaskHandle().logWarn(msg, params);
    }

    public static void error(Throwable throwable, String msg, Object... params) {
        getTaskHandle().logError(throwable, msg, params);
    }

    public static void error(String msg, Object... params) {
        getTaskHandle().logError(null, msg, params);
    }

    @Override
    public void run() {
        ThreadContext.set("CURRENT_TASK", this);
        try {
            if (taskStatus != TaskStatus.Pending) {
                log.warn("任务状态错误，无法运行，任务：{}，当前状态：{}", taskName, taskStatus.getTxt());
                return;
            }
            taskStatus = TaskStatus.Running;
            startTime = LocalDateTime.now();
            taskScheduleRecodeService.start(this);
            if (fnHandle == null) {
                endTime = LocalDateTime.now();
                taskStatus = TaskStatus.Error;
                taskScheduleRecodeService.end(this);
                log.error("任务执行失败：{}，任务处理函数不存在：{}", taskName, fn);
                return;
            }
            this.logInfo("开始执行");
            boolean exec = fnHandle.exec();
            endTime = LocalDateTime.now();
            taskStatus = exec ? TaskStatus.Completed : TaskStatus.Error;
            taskScheduleRecodeService.end(this);
            this.logInfo("执行完成");
        } catch (Exception e) {
            log.error("错误：任务执行失败", e);
        } finally {
            ThreadContext.remove("CURRENT_TASK");
        }
    }

    public void pending() {
        this.taskStatus = TaskStatus.Pending;
        taskScheduleRecodeService.pending(this);
    }

    public void logDebug(String msg, Object... params) {
        if (this.logLevel != TaskLogLevel.DEBUG) return;
        taskScheduleRecodeService.log(this, TaskLogLevel.DEBUG, null, msg, params);
    }

    public void logInfo(String msg, Object... params) {
        if (this.logLevel != TaskLogLevel.DEBUG
            && this.logLevel != TaskLogLevel.INFO) return;
        taskScheduleRecodeService.log(this, TaskLogLevel.INFO, null, msg, params);
    }

    public void logWarn(String msg, Object... params) {
        if (this.logLevel != TaskLogLevel.DEBUG
            && this.logLevel != TaskLogLevel.INFO
            && this.logLevel != TaskLogLevel.WARN) return;
        taskScheduleRecodeService.log(this, TaskLogLevel.WARN, null, msg, params);
    }

    public void logError(Throwable throwable, String msg, Object... params) {
        if (this.logLevel != TaskLogLevel.DEBUG
            && this.logLevel != TaskLogLevel.INFO
            && this.logLevel != TaskLogLevel.WARN
            && this.logLevel != TaskLogLevel.ERROR) return;
        taskScheduleRecodeService.log(this, TaskLogLevel.ERROR, throwable, msg, params);
    }
}
