package org.xyzh.crontab.service.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xyzh.api.crontab.CrontabService;
import org.xyzh.api.crontab.EmailDefaultService;
import org.xyzh.api.crontab.EmailRecipientService;
import org.xyzh.common.core.domain.ResultDomain;
import org.xyzh.common.core.page.PageDomain;
import org.xyzh.common.core.page.PageParam;
import org.xyzh.common.dto.crontab.CreateTaskRequest;
import org.xyzh.common.dto.crontab.TbCrontabEmailDefault;
import org.xyzh.common.dto.crontab.TbCrontabEmailRecipient;
import org.xyzh.common.dto.crontab.TbCrontabTask;
import org.xyzh.common.dto.user.TbSysUser;
import org.xyzh.common.dto.crontab.TbCrontabLog;
import org.xyzh.common.utils.IDUtils;
import org.xyzh.common.vo.UserDeptRoleVO;
import org.xyzh.crontab.mapper.CrontabTaskMapper;
import org.xyzh.crontab.mapper.CrontabLogMapper;
import org.xyzh.crontab.scheduler.SchedulerManager;
import org.xyzh.api.system.permission.ResourcePermissionService;
import org.xyzh.common.core.enums.ResourceType;
import org.xyzh.system.utils.LoginUtil;

import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @description 定时任务服务实现类
 * @filename CrontabServiceImpl.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-10-25
 */
@Service
public class CrontabServiceImpl implements CrontabService {

    private static final Logger logger = LoggerFactory.getLogger(CrontabServiceImpl.class);

    @Autowired
    private CrontabTaskMapper taskMapper;

    @Autowired
    private CrontabLogMapper logMapper;

    @Autowired
    private SchedulerManager schedulerManager;

    @Autowired
    private ResourcePermissionService resourcePermissionService;

    @Autowired
    private EmailDefaultService emailDefaultService;

    @Autowired
    private EmailRecipientService emailRecipientService;

    // ----------------定时任务管理--------------------------------

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabTask> createTask(TbCrontabTask task) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            // 验证Cron表达式
            if (!CronExpression.isValidExpression(task.getCronExpression())) {
                resultDomain.fail("Cron表达式格式不正确");
                return resultDomain;
            }

            // 生成ID
            task.setID(IDUtils.generateID());
            task.setTaskId(IDUtils.generateID());
            task.setCreateTime(new Date());
            task.setDeleted(false);

            // 默认值
            if (task.getStatus() == null) {
                task.setStatus(0); // 默认暂停
            }
            if (task.getConcurrent() == null) {
                task.setConcurrent(0); // 默认不允许并发
            }
            if (task.getMisfirePolicy() == null) {
                task.setMisfirePolicy(1); // 默认立即执行
            }

            int result = taskMapper.insertTask(task);
            if (result > 0) {
                logger.info("创建定时任务成功: {}", task.getTaskName());
                
                // 创建定时任务资源权限
                try {
                    List<UserDeptRoleVO> userDeptRoles = LoginUtil.getCurrentDeptRole();
                    if (userDeptRoles != null && !userDeptRoles.isEmpty()) {
                        resourcePermissionService.createResourcePermission(
                            ResourceType.CRONTAB_TASK.getCode(), 
                            task.getTaskId(),
                            userDeptRoles.get(0)
                        );
                        logger.info("创建定时任务权限成功: {}", task.getTaskName());
                    }
                } catch (Exception e) {
                    logger.error("创建定时任务权限异常，但不影响任务创建: {}", e.getMessage(), e);
                }
                
                // 如果任务状态为启动，则立即调度
                if (task.getStatus() == 1) {
                    schedulerManager.scheduleTask(task);
                }
                
                resultDomain.success("创建定时任务成功", task);
            } else {
                resultDomain.fail("创建定时任务失败");
            }
        } catch (Exception e) {
            logger.error("创建定时任务异常: ", e);
            resultDomain.fail("创建定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabTask> createTaskWithRecipients(CreateTaskRequest request) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            TbCrontabTask task = request.getTask();
            TbSysUser user = LoginUtil.getCurrentUser();
            task.setCreator(user.getID());
            // 1. 创建任务
            ResultDomain<TbCrontabTask> createResult = createTask(task);
            if (!createResult.isSuccess()) {
                return createResult;
            }
            
            String taskId = task.getTaskId();
            String metaId = request.getMetaId();
            
            
            // 3. 添加额外的接收人
            if (request.getAdditionalRecipients() != null && !request.getAdditionalRecipients().isEmpty()) {
                try {
                    for (CreateTaskRequest.RecipientUserInfo userInfo : request.getAdditionalRecipients()) {
                        TbCrontabEmailRecipient recipient = new TbCrontabEmailRecipient();
                        recipient.setTaskId(taskId);
                        recipient.setUserId(userInfo.getUserId());
                        recipient.setEmail(userInfo.getUserEmail());
                        recipient.setName(userInfo.getUsername());
                        recipient.setCreator(task.getCreator());
                        
                        emailRecipientService.createRecipient(recipient);
                    }
                    logger.info("为任务{}添加了{}个额外接收人", taskId, request.getAdditionalRecipients().size());
                } catch (Exception e) {
                    logger.error("添加额外接收人异常，但不影响任务创建: {}", e.getMessage(), e);
                }
            }
            
            resultDomain.success("创建任务并绑定接收人成功", task);
        } catch (Exception e) {
            logger.error("创建任务并绑定接收人异常: ", e);
            resultDomain.fail("创建任务并绑定接收人异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabTask> updateTaskWithRecipients(CreateTaskRequest request) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            TbCrontabTask task = request.getTask();
            
            // 1. 更新任务
            ResultDomain<TbCrontabTask> updateResult = updateTask(task);
            if (!updateResult.isSuccess()) {
                return updateResult;
            }
            
            String taskId = task.getTaskId();
            String metaId = request.getMetaId();
            
            // 2. 先删除该任务的旧接收人
            try {
                emailRecipientService.deleteRecipientsByTaskId(taskId);
                logger.info("已删除任务{}的旧接收人配置", taskId);
            } catch (Exception e) {
                logger.error("删除旧接收人异常: {}", e.getMessage(), e);
            }
            
            // 4. 添加额外的接收人
            if (request.getAdditionalRecipients() != null && !request.getAdditionalRecipients().isEmpty()) {
                try {
                    for (CreateTaskRequest.RecipientUserInfo userInfo : request.getAdditionalRecipients()) {
                        TbCrontabEmailRecipient recipient = new TbCrontabEmailRecipient();
                        recipient.setTaskId(taskId);
                        recipient.setUserId(userInfo.getUserId());
                        recipient.setEmail(userInfo.getUserEmail());
                        recipient.setName(userInfo.getUsername());
                        recipient.setUpdater(task.getUpdater());
                        
                        emailRecipientService.createRecipient(recipient);
                    }
                    logger.info("为任务{}添加了{}个额外接收人", taskId, request.getAdditionalRecipients().size());
                } catch (Exception e) {
                    logger.error("添加额外接收人异常，但不影响任务更新: {}", e.getMessage(), e);
                }
            }
            
            resultDomain.success("更新任务并更新接收人成功", task);
        } catch (Exception e) {
            logger.error("更新任务并更新接收人异常: ", e);
            resultDomain.fail("更新任务并更新接收人异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabTask> updateTask(TbCrontabTask task) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (task.getTaskId() == null) {
                resultDomain.fail("任务ID不能为空");
                return resultDomain;
            }

            // 验证Cron表达式
            if (task.getCronExpression() != null && !CronExpression.isValidExpression(task.getCronExpression())) {
                resultDomain.fail("Cron表达式格式不正确");
                return resultDomain;
            }

            task.setUpdateTime(new Date());
            int result = taskMapper.updateTask(task);
            
            if (result > 0) {
                logger.info("更新定时任务成功: {}", task.getTaskName());
                
                // 重新调度任务
                TbCrontabTask dbTask = taskMapper.selectTaskById(task.getTaskId());
                if (dbTask != null && dbTask.getStatus() == 1) {
                    schedulerManager.rescheduleTask(dbTask);
                }
                
                resultDomain.success("更新定时任务成功", task);
            } else {
                resultDomain.fail("更新定时任务失败");
            }
        } catch (Exception e) {
            logger.error("更新定时任务异常: ", e);
            resultDomain.fail("更新定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabTask> deleteTask(String taskId) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (taskId == null || taskId.isEmpty()) {
                resultDomain.fail("任务ID不能为空");
                return resultDomain;
            }

            // 先停止任务调度
            TbCrontabTask task = taskMapper.selectTaskById(taskId);
            if (task != null && task.getStatus() == 1) {
                schedulerManager.unscheduleTask(task);
            }

            int result = taskMapper.deleteTask(taskId);
            if (result > 0) {
                logger.info("删除定时任务成功，任务ID: {}", taskId);
                resultDomain.success("删除定时任务成功", (TbCrontabTask) null);
            } else {
                resultDomain.fail("删除定时任务失败");
            }
        } catch (Exception e) {
            logger.error("删除定时任务异常: ", e);
            resultDomain.fail("删除定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<TbCrontabTask> getTaskById(String taskId) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (taskId == null || taskId.isEmpty()) {
                resultDomain.fail("任务ID不能为空");
                return resultDomain;
            }

            TbCrontabTask task = taskMapper.selectTaskById(taskId);
            if (task != null) {
                resultDomain.success("查询成功", task);
            } else {
                resultDomain.fail("任务不存在");
            }
        } catch (Exception e) {
            logger.error("查询定时任务异常: ", e);
            resultDomain.fail("查询定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<TbCrontabTask> getTaskList(TbCrontabTask filter) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (filter == null) {
                filter = new TbCrontabTask();
            }
            filter.setDeleted(false);
            
            List<UserDeptRoleVO> userDeptRoles = LoginUtil.getCurrentDeptRole();
            List<TbCrontabTask> list = taskMapper.selectTaskList(filter, userDeptRoles);
            resultDomain.success("查询成功", list);
        } catch (Exception e) {
            logger.error("查询定时任务列表异常: ", e);
            resultDomain.fail("查询定时任务列表异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<TbCrontabTask> getTaskPage(TbCrontabTask filter, PageParam pageParam) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (filter == null) {
                filter = new TbCrontabTask();
            }
            filter.setDeleted(false);
            
            if (pageParam == null) {
                pageParam = new PageParam();
            }

            List<UserDeptRoleVO> userDeptRoles = LoginUtil.getCurrentDeptRole();
            List<TbCrontabTask> list = taskMapper.selectTaskPage(filter, pageParam, userDeptRoles);
            int total = taskMapper.countSelectTask(filter, userDeptRoles);
            
            PageDomain<TbCrontabTask> pageDomain = new PageDomain<>();
            pageDomain.setDataList(list);
            pageParam.setTotalElements(total);
            pageParam.setTotalPages((int) Math.ceil((double) total / pageParam.getPageSize()));
            pageDomain.setPageParam(pageParam);
            resultDomain.success("查询成功", pageDomain);
        } catch (Exception e) {
            logger.error("分页查询定时任务异常: ", e);
            resultDomain.fail("分页查询定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabTask> startTask(String taskId) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (taskId == null || taskId.isEmpty()) {
                resultDomain.fail("任务ID不能为空");
                return resultDomain;
            }

            TbCrontabTask task = taskMapper.selectTaskById(taskId);
            if (task == null) {
                resultDomain.fail("任务不存在");
                return resultDomain;
            }

            if (task.getStatus() == 1) {
                resultDomain.fail("任务已在运行中");
                return resultDomain;
            }

            // 更新状态为运行中
            int result = taskMapper.updateTaskStatus(taskId, 1);
            if (result > 0) {
                task.setStatus(1);
                // 调度任务
                schedulerManager.scheduleTask(task);
                
                logger.info("启动定时任务成功: {}", task.getTaskName());
                resultDomain.success("启动定时任务成功", task);
            } else {
                resultDomain.fail("启动定时任务失败");
            }
        } catch (Exception e) {
            logger.error("启动定时任务异常: ", e);
            resultDomain.fail("启动定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabTask> pauseTask(String taskId) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (taskId == null || taskId.isEmpty()) {
                resultDomain.fail("任务ID不能为空");
                return resultDomain;
            }

            TbCrontabTask task = taskMapper.selectTaskById(taskId);
            if (task == null) {
                resultDomain.fail("任务不存在");
                return resultDomain;
            }

            if (task.getStatus() == 0) {
                resultDomain.fail("任务已暂停");
                return resultDomain;
            }

            // 取消调度
            schedulerManager.unscheduleTask(task);

            // 更新状态为暂停
            int result = taskMapper.updateTaskStatus(taskId, 0);
            if (result > 0) {
                task.setStatus(0);
                logger.info("暂停定时任务成功: {}", task.getTaskName());
                resultDomain.success("暂停定时任务成功", task);
            } else {
                resultDomain.fail("暂停定时任务失败");
            }
        } catch (Exception e) {
            logger.error("暂停定时任务异常: ", e);
            resultDomain.fail("暂停定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<TbCrontabTask> executeTaskOnce(String taskId) {
        ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
        try {
            if (taskId == null || taskId.isEmpty()) {
                resultDomain.fail("任务ID不能为空");
                return resultDomain;
            }

            TbCrontabTask task = taskMapper.selectTaskById(taskId);
            if (task == null) {
                resultDomain.fail("任务不存在");
                return resultDomain;
            }

            // 立即执行一次
            schedulerManager.executeTaskOnce(task);
            
            logger.info("立即执行定时任务: {}", task.getTaskName());
            resultDomain.success("立即执行定时任务成功", task);
        } catch (Exception e) {
            logger.error("立即执行定时任务异常: ", e);
            resultDomain.fail("立即执行定时任务异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<String> validateCronExpression(String cronExpression) {
        ResultDomain<String> resultDomain = new ResultDomain<>();
        try {
            if (cronExpression == null || cronExpression.isEmpty()) {
                resultDomain.fail("Cron表达式不能为空");
                return resultDomain;
            }

            if (!CronExpression.isValidExpression(cronExpression)) {
                resultDomain.fail("Cron表达式格式不正确");
                return resultDomain;
            }

            // 计算下次执行时间
            CronExpression cron = CronExpression.parse(cronExpression);
            LocalDateTime nextExecution = cron.next(LocalDateTime.now());
            
            if (nextExecution != null) {
                String message = "Cron表达式有效，下次执行时间: " + nextExecution;
                resultDomain.success("验证成功", message);
            } else {
                resultDomain.fail("无法计算下次执行时间");
            }
        } catch (Exception e) {
            logger.error("验证Cron表达式异常: ", e);
            resultDomain.fail("验证Cron表达式异常: " + e.getMessage());
        }
        return resultDomain;
    }

    // ----------------定时任务日志--------------------------------

    @Override
    public ResultDomain<TbCrontabLog> getLogsByTaskId(String taskId) {
        ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
        try {
            if (taskId == null || taskId.isEmpty()) {
                resultDomain.fail("任务ID不能为空");
                return resultDomain;
            }

            List<TbCrontabLog> list = logMapper.selectLogsByTaskId(taskId);
            resultDomain.success("查询成功", list);
        } catch (Exception e) {
            logger.error("查询任务日志异常: ", e);
            resultDomain.fail("查询任务日志异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<TbCrontabLog> getLogList(TbCrontabLog filter) {
        ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
        try {
            if (filter == null) {
                filter = new TbCrontabLog();
            }
            filter.setDeleted(false);
            
            List<TbCrontabLog> list = logMapper.selectLogList(filter);
            resultDomain.success("查询成功", list);
        } catch (Exception e) {
            logger.error("查询日志列表异常: ", e);
            resultDomain.fail("查询日志列表异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<TbCrontabLog> getLogPage(TbCrontabLog filter, PageParam pageParam) {
        ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
        try {
            if (filter == null) {
                filter = new TbCrontabLog();
            }
            filter.setDeleted(false);
            
            if (pageParam == null) {
                pageParam = new PageParam();
            }

            List<TbCrontabLog> list = logMapper.selectLogPage(filter, pageParam);
            resultDomain.success("查询成功", list);
        } catch (Exception e) {
            logger.error("分页查询日志异常: ", e);
            resultDomain.fail("分页查询日志异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    public ResultDomain<TbCrontabLog> getLogById(String logId) {
        ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
        try {
            if (logId == null || logId.isEmpty()) {
                resultDomain.fail("日志ID不能为空");
                return resultDomain;
            }

            TbCrontabLog log = logMapper.selectLogById(logId);
            if (log != null) {
                resultDomain.success("查询成功", log);
            } else {
                resultDomain.fail("日志不存在");
            }
        } catch (Exception e) {
            logger.error("查询日志详情异常: ", e);
            resultDomain.fail("查询日志详情异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<Integer> cleanLogs(Integer days) {
        ResultDomain<Integer> resultDomain = new ResultDomain<>();
        try {
            if (days == null || days <= 0) {
                resultDomain.fail("天数参数无效");
                return resultDomain;
            }

            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.DAY_OF_MONTH, -days);
            Date beforeDate = calendar.getTime();

            int count = logMapper.cleanLogsByDate(beforeDate);
            logger.info("清理{}天前的日志，共{}条", days, count);
            
            resultDomain.success("清理成功", count);
        } catch (Exception e) {
            logger.error("清理日志异常: ", e);
            resultDomain.fail("清理日志异常: " + e.getMessage());
        }
        return resultDomain;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultDomain<TbCrontabLog> deleteLog(String logId) {
        ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
        try {
            if (logId == null || logId.isEmpty()) {
                resultDomain.fail("日志ID不能为空");
                return resultDomain;
            }

            int result = logMapper.deleteLog(logId);
            if (result > 0) {
                logger.info("删除日志成功，日志ID: {}", logId);
                resultDomain.success("删除日志成功", (TbCrontabLog) null);
            } else {
                resultDomain.fail("删除日志失败");
            }
        } catch (Exception e) {
            logger.error("删除日志异常: ", e);
            resultDomain.fail("删除日志异常: " + e.getMessage());
        }
        return resultDomain;
    }
}
