package com.erp.task.service;

import com.erp.task.entity.ScheduledTask;
import com.erp.task.entity.TaskExecutionLog;
import com.erp.task.exception.TaskException;
import com.erp.task.monitor.TaskMonitor;
import com.erp.task.retry.RetryHandler;
import com.erp.task.util.CronUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;

/**
 * 任务执行器
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TaskExecutor {

    private final ApplicationContext applicationContext;
    private final TaskExecutionLogService logService;
    private final RetryHandler retryHandler;
    private final TaskMonitor taskMonitor;
    private final ObjectMapper objectMapper;

    private final Map<Long, Future<?>> runningTasks = new ConcurrentHashMap<>();
    private final Map<Long, Long> taskLogIds = new ConcurrentHashMap<>();

    /**
     * 执行任务
     */
    @Async("taskExecutor")
    public void execute(ScheduledTask task) {
        String batchNo = UUID.randomUUID().toString().replace("-", "");
        log.info("开始执行任务: {}, batchNo: {}", task.getId(), batchNo);

        // 创建执行记录
        TaskExecutionLog taskLog = logService.createLog(
                task.getId(),
                task.getTaskName(),
                task.getTaskGroup(),
                batchNo,
                task.getTaskParams());

        taskLogIds.put(task.getId(), taskLog.getId());
        taskMonitor.recordExecution(task.getId());

        Future<?> future = null;
        ExecutorService executor = null;

        try {
            // 创建单独的执行器
            executor = Executors.newCachedThreadPool();
            Future<Object> taskFuture = executor.submit(() -> {
                return executeTaskLogic(task);
            });

            runningTasks.put(task.getId(), taskFuture);

            // 处理超时
            if (task.getTimeout() != null && task.getTimeout() > 0) {
                try {
                    Object result = taskFuture.get(task.getTimeout(), TimeUnit.SECONDS);
                    logService.logSuccess(taskLog.getId(), objectMapper.writeValueAsString(result));
                    taskMonitor.recordSuccess(task.getId());
                } catch (TimeoutException e) {
                    taskFuture.cancel(true);
                    handleFailure(task, taskLog, TaskException.timeout(task.getId(), task.getTimeout()));
                }
            } else {
                Object result = taskFuture.get();
                logService.logSuccess(taskLog.getId(), objectMapper.writeValueAsString(result));
                taskMonitor.recordSuccess(task.getId());
            }

        } catch (Exception e) {
            handleFailure(task, taskLog, e);
        } finally {
            runningTasks.remove(task.getId());
            taskLogIds.remove(task.getId());
            if (executor != null) {
                executor.shutdown();
            }
        }
    }

    /**
     * 执行任务逻辑
     */
    private Object executeTaskLogic(ScheduledTask task) throws Exception {
        switch (task.getTaskType()) {
            case "BEAN":
                return executeBeanTask(task);
            case "CLASS":
                return executeClassTask(task);
            case "XXL_JOB":
                // XXL-Job模式由XXL-Job调度器触发，此处处理本地执行
                return executeBeanTask(task);
            default:
                throw new IllegalArgumentException("不支持的任务类型: " + task.getTaskType());
        }
    }

    /**
     * 执行Spring Bean任务
     */
    @SuppressWarnings("unchecked")
    private Object executeBeanTask(ScheduledTask task) throws Exception {
        String beanName = task.getTaskClass();
        Object bean = applicationContext.getBean(beanName);

        String methodName = task.getMethodName();
        if (methodName == null || methodName.isEmpty()) {
            methodName = "execute";
        }

        // 解析参数
        Object params = null;
        if (task.getTaskParams() != null && !task.getTaskParams().isEmpty()) {
            try {
                params = objectMapper.readValue(task.getTaskParams(), Map.class);
            } catch (Exception e) {
                params = task.getTaskParams();
            }
        }

        // 反射调用方法
        java.lang.reflect.Method method;
        if (params != null) {
            method = bean.getClass().getMethod(methodName, Object.class);
            return method.invoke(bean, params);
        } else {
            method = bean.getClass().getMethod(methodName);
            return method.invoke(bean);
        }
    }

    /**
     * 执行Class任务（反射调用）
     */
    @SuppressWarnings("unchecked")
    private Object executeClassTask(ScheduledTask task) throws Exception {
        Class<?> clazz = Class.forName(task.getTaskClass());
        Object instance = clazz.getDeclaredConstructor().newInstance();

        String methodName = task.getMethodName();
        if (methodName == null || methodName.isEmpty()) {
            methodName = "execute";
        }

        java.lang.reflect.Method method = clazz.getMethod(methodName);
        return method.invoke(instance);
    }

    /**
     * 处理失败
     */
    private void handleFailure(ScheduledTask task, TaskExecutionLog taskLog, Exception e) {
        String errorMessage = e.getMessage();
        String errorTrace = getErrorTrace(e);

        log.error("任务执行失败: {}, error: {}", task.getId(), errorMessage, e);

        logService.logFailure(taskLog.getId(), errorMessage, errorTrace);
        taskMonitor.recordFailure(task.getId());

        // 检查是否需要重试
        if (task.getMaxRetries() != null && task.getMaxRetries() > 0 && taskLog.getRetryCount() < task.getMaxRetries()) {
            log.info("任务 {} 准备重试，当前重试次数: {}", task.getId(), taskLog.getRetryCount());
            retryHandler.scheduleRetry(task, taskLog.getId(), task.getRetryInterval());
        } else {
            // 触发告警
            taskMonitor.alertOnFailure(task, errorMessage);
        }
    }

    /**
     * 获取错误堆栈
     */
    private String getErrorTrace(Exception e) {
        StringBuilder sb = new StringBuilder();
        for (StackTraceElement element : e.getStackTrace()) {
            sb.append(element.toString()).append("\n");
            if (sb.length() > 2000) {
                sb.append("... (truncated)");
                break;
            }
        }
        return sb.toString();
    }

    /**
     * 取消任务
     */
    public boolean cancelTask(Long taskId) {
        Future<?> future = runningTasks.get(taskId);
        if (future != null && !future.isDone()) {
            future.cancel(true);
            Long logId = taskLogIds.get(taskId);
            if (logId != null) {
                logService.logFailure(logId, "任务被手动取消", null);
            }
            runningTasks.remove(taskId);
            taskLogIds.remove(taskId);
            log.info("任务已取消: {}", taskId);
            return true;
        }
        return false;
    }

    /**
     * 检查任务是否正在运行
     */
    public boolean isRunning(Long taskId) {
        Future<?> future = runningTasks.get(taskId);
        return future != null && !future.isDone();
    }

    /**
     * 获取正在运行的任务数
     */
    public int getRunningCount() {
        return (int) runningTasks.values().stream().filter(f -> !f.isDone()).count();
    }
}
