package com.seer.teach.admin.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.seer.teach.admin.convert.AdminAiTaskConvert;
import com.seer.teach.admin.request.AdminAiTaskPageReq;
import com.seer.teach.admin.request.AdminAiTaskReq;
import com.seer.teach.admin.request.GenerateBankQuestionReq;
import com.seer.teach.admin.request.GenerateTeachGoalReq;
import com.seer.teach.admin.request.GenerateTaskReq;
import com.seer.teach.admin.response.AdminAiTaskResp;
import com.seer.teach.common.PageListBean;
import com.seer.teach.common.constants.CommonConstant;
import com.seer.teach.common.enums.AiScenarioCodeEnum;
import com.seer.teach.common.utils.HostIpResolver;
import com.seer.teach.common.utils.PageConverterUtils;
import com.seer.teach.common.utils.RedisDistributedLock;
import com.seer.teach.teacher.module.entity.AiTaskEntity;
import com.seer.teach.teacher.service.IAiTaskService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import jakarta.annotation.PreDestroy;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * AI任务管理服务
 *
 * @author System
 * @since 2025-12-11
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AdminAiTaskService {

    private final IAiTaskService aiTaskService;

    private final BankQuestionGenerationService bankQuestionGenerationService;
    private final TeachGoalGenerationService teachGoalGenerationService;
    private final TeachTextGenerationService teachTextGenerationService;
    private final VideoScriptGenerationService videoScriptGenerationService;
    private final RedisDistributedLock redisDistributedLock;
    private final StringRedisTemplate stringRedisTemplate;
    private final RestTemplate restTemplate;
    private final NacosDiscoveryProperties nacosDiscoveryProperties;

    @Value("${spring.application.name}")
    private String applicationName;

    // 用于存储正在进行中的任务Future，以便能够取消任务
    private final Map<String, CompletableFuture<Void>> taskFutures = new ConcurrentHashMap<>();

    private static final String TASK_LOCK_PREFIX = "ai_task_lock:";
    private static final long LOCK_EXPIRE_TIME = 600;

    /**
     * 分页查询AI任务列表
     *
     * @param pageRequest 分页查询参数
     * @return 分页结果
     */
    public PageListBean<AdminAiTaskResp> pageList(AdminAiTaskPageReq pageRequest) {
        log.info("分页查询AI任务列表，请求参数: {}", pageRequest);
        IPage<AiTaskEntity> page = new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());

        LambdaQueryWrapper<AiTaskEntity> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(pageRequest.getTaskId())) {
            wrapper.like(AiTaskEntity::getTaskId, pageRequest.getTaskId());
        }

        if (StrUtil.isNotBlank(pageRequest.getStatus())) {
            wrapper.eq(AiTaskEntity::getStatus, pageRequest.getStatus());
        }


        wrapper.orderByDesc(AiTaskEntity::getTaskCreatedTime);
        IPage<AiTaskEntity> result = aiTaskService.page(page, wrapper);
        PageListBean<AdminAiTaskResp> resp = PageConverterUtils.convertPageListBean(result, AdminAiTaskConvert.INSTANCE::entityListToRespList);
        log.info("分页查询AI任务列表完成，返回结果数量: {}", resp.getList().size());
        return resp;
    }

    /**
     * 根据ID获取AI任务详情
     *
     * @param id 任务ID
     * @return 任务详情
     */
    public AdminAiTaskResp getDetail(Long id) {
        log.info("根据ID获取AI任务详情，ID: {}", id);
        AiTaskEntity entity = aiTaskService.getById(id);
        AdminAiTaskResp resp = AdminAiTaskConvert.INSTANCE.entityToResp(entity);
        log.info("根据ID获取AI任务详情完成，结果: {}", resp);
        return resp;
    }

    /**
     * 更新AI任务
     *
     * @param requestParam 请求参数
     * @return 是否成功
     */
    public Boolean updateById(AdminAiTaskReq requestParam) {
        log.info("更新AI任务，请求参数: {}", requestParam);
        AiTaskEntity entity = AdminAiTaskConvert.INSTANCE.reqToEntity(requestParam);
        boolean updated = aiTaskService.updateById(entity);
        log.info("更新AI任务完成，结果: {}，更新的实体ID: {}", updated, entity.getId());
        return updated;
    }

    /**
     * 删除AI任务
     *
     * @param id 任务ID
     * @return 是否成功
     */
    public Boolean deleteById(Long id) {
        log.info("删除AI任务，ID: {}", id);
        boolean removed = aiTaskService.removeById(id);
        log.info("删除AI任务完成，结果: {}，删除的实体ID: {}", removed, id);
        return removed;
    }

    /**
     * 获取AI任务列表
     *
     * @param queryRequest 查询参数
     * @return 任务列表
     */
    public List<AdminAiTaskResp> list(AdminAiTaskPageReq queryRequest) {
        log.info("获取AI任务列表，请求参数: {}", queryRequest);

        LambdaQueryWrapper<AiTaskEntity> wrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(queryRequest.getTaskId())) {
            wrapper.like(AiTaskEntity::getTaskId, queryRequest.getTaskId());
        }

        if (StrUtil.isNotBlank(queryRequest.getStatus())) {
            wrapper.eq(AiTaskEntity::getStatus, queryRequest.getStatus());
        }

        wrapper.orderByDesc(AiTaskEntity::getCreateTime);
        List<AiTaskEntity> entities = aiTaskService.list(wrapper);
        List<AdminAiTaskResp> respList = AdminAiTaskConvert.INSTANCE.entityListToRespList(entities);
        log.info("获取AI任务列表完成，返回结果数量: {}", respList.size());
        return respList;
    }

    /**
     * 新增AI任务
     *
     * @param requestParam 请求参数
     * @return 是否成功
     */
    public Boolean start(AdminAiTaskReq requestParam) {
        log.info("新增AI任务，请求参数: {}", requestParam);
        AiTaskEntity entity = AdminAiTaskConvert.INSTANCE.reqToEntity(requestParam);
        entity.setTaskCreatedTime(LocalDateTime.now());
        entity.setTaskId(UUID.randomUUID().toString());
        entity.setIp(HostIpResolver.getHostIp());
        boolean saved = aiTaskService.save(entity);
        if (!saved) {
            log.error("保存AI任务失败，请检查参数");
            return false;
        }
        String scenarioCode = requestParam.getScenarioCode();
        try {
            // 异步执行任务避免阻塞主线程
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                String taskLockKey = TASK_LOCK_PREFIX + "process:" + entity.getId();
                String taskLockValue = redisDistributedLock.tryLock(taskLockKey, LOCK_EXPIRE_TIME, TimeUnit.SECONDS);

                if (taskLockValue == null) {
                    log.warn("任务已在其他节点处理，任务ID: {}", entity.getId());
                    updateTaskStatus(entity.getId(), "cancelled");
                    return;
                }
                try {
                    GenerateTaskReq textReq = JSONUtil.toBean(requestParam.getTaskParams(), GenerateTaskReq.class);
                    textReq.setTaskId(entity.getTaskId());
                    Object result = null;
                    if (AiScenarioCodeEnum.KNOWLEDGE_POINT_GENERATE_QUESTIONS.getCode().equals(scenarioCode)) {
                        // 知识点生成题目场景
                        textReq.setScenarioCode(AiScenarioCodeEnum.KNOWLEDGE_POINT_GENERATE_QUESTIONS.getCode());
                        result = bankQuestionGenerationService.generateAndSaveAllBankQuestions(textReq);
                    } else if (AiScenarioCodeEnum.KNOWLEDGE_POINT_GENERATE_TEACH_GOALS.getCode().equals(scenarioCode)) {
                        textReq.setScenarioCode(AiScenarioCodeEnum.KNOWLEDGE_POINT_GENERATE_TEACH_GOALS.getCode());
                        result = teachGoalGenerationService.generateAndSaveAllTeachGoals(textReq);
                    }else if (AiScenarioCodeEnum.GENERATE_TEACH_TEXTS_FROM_GOALS.getCode().equals(scenarioCode)) {
                        textReq.setTaskId(entity.getTaskId());
                        textReq.setScenarioCode(AiScenarioCodeEnum.GENERATE_TEACH_TEXTS_FROM_GOALS.getCode());
                        result = teachTextGenerationService.generateAndSaveAllTeachTexts(textReq);
                    } else if (AiScenarioCodeEnum.GENERATE_VIDEO_SCRIPT_FROM_TEACH_TEXTS.getCode().equals(scenarioCode)) {
                        textReq.setTaskId(entity.getTaskId());
                        textReq.setScenarioCode(AiScenarioCodeEnum.GENERATE_VIDEO_SCRIPT_FROM_TEACH_TEXTS.getCode());
                        result = videoScriptGenerationService.generateAndSaveAllVideoScripts(textReq);
                    }
                    updateTaskStatus(entity.getId(), "success",result);
                } catch (Exception e) {
                    log.error("AI生成任务失败，场景编码：{}",scenarioCode, e);
                    updateTaskStatus(entity.getId(), "failed",e.getMessage());
                } finally {
                    // 释放锁并从任务映射中移除已完成的任务
                    redisDistributedLock.unlock(taskLockKey, taskLockValue);
                    taskFutures.remove(entity.getTaskId());
                    // 清除取消标记
                    stringRedisTemplate.delete(CommonConstant.TASK_CANCEL_PREFIX + entity.getTaskId());
                }
            });
            taskFutures.put(entity.getTaskId(), future);
            // 更新任务状态为处理中
            entity.setStatus("processing");
            aiTaskService.updateById(entity);
        } catch (Exception e) {
            log.error("启动AI任务异常: ", e);
            // 如果启动任务出现异常，标记为失败
            entity.setStatus("failed");
            aiTaskService.updateById(entity);
            return false;
        }
        log.info("新增AI任务完成，结果: {}，保存的实体ID: {}", saved, entity.getId());
        return true;
    }


    /**
     * 终止AI任务
     *
     * @param id 任务ID
     * @return 是否成功
     */
    public Boolean stopTask(Long id) {
        log.info("终止AI任务，ID: {}", id);
        AiTaskEntity entity = aiTaskService.getById(id);
        if (entity == null) {
            log.warn("尝试终止不存在的任务，ID: {}", id);
            return false;
        }

        // 只有进行中的任务才能被终止
        if (!"processing".equals(entity.getStatus())) {
            log.warn("尝试终止非进行中任务，当前状态: {}，ID: {}", entity.getStatus(), id);
            return false;
        }

        // 检查任务运行的主机IP是否与当前节点一致
        String currentIp = HostIpResolver.getHostIp();
        if (!currentIp.equals(entity.getIp())) {
            // IP不一致，需要调用远程节点的停止接口
            log.info("任务运行在不同节点上，当前节点IP: {}，任务所在节点IP: {}，将调用远程节点接口", currentIp, entity.getIp());
            return stopRemoteTask(entity, id);
        }

        // 使用分布式锁确保任务终止的原子性
        String lockKey = TASK_LOCK_PREFIX + "stop:" + id;
        String lockValue = redisDistributedLock.tryLock(lockKey, LOCK_EXPIRE_TIME, TimeUnit.SECONDS);

        if (lockValue == null) {
            log.warn("获取任务终止锁失败，任务ID: {}", id);
            return false;
        }

        try {
            stringRedisTemplate.opsForValue().set(CommonConstant.TASK_CANCEL_PREFIX + entity.getTaskId(), "true", LOCK_EXPIRE_TIME, TimeUnit.SECONDS);

            // 尝试取消任务
            CompletableFuture<Void> future = taskFutures.get(entity.getTaskId());
            boolean cancelled = false;
            if (future != null && !future.isDone()) {
                cancelled = future.cancel(true);
            } else {
                log.warn("未能找到对应的任务Future，任务ID: {}", id);
            }

            // 更新任务状态
            if (cancelled) {
                updateTaskStatus(entity.getId(), "cancelled");
                log.info("成功终止AI任务，ID: {}", id);
            } else {
                updateTaskStatus(entity.getId(), "interrupted");
                log.warn("未能成功终止AI任务，ID: {}", id);
            }

            // 从任务映射中移除
            taskFutures.remove(entity.getTaskId());

            log.info("终止AI任务完成，结果: {}，终止的实体ID: {}", cancelled, id);
            return cancelled;
        } finally {
            // 释放终止锁
            redisDistributedLock.unlock(lockKey, lockValue);
        }
    }

    /**
     * 调用远程节点停止任务
     *
     * @param entity 任务实体
     * @param id     任务ID
     * @return 是否成功
     */
    private Boolean stopRemoteTask(AiTaskEntity entity, Long id) {
        try {
            NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
            List<Instance> instances = namingService.getAllInstances(applicationName);

            // 查找匹配IP的实例
            Instance targetInstance = null;
            for (Instance instance : instances) {
                if (entity.getIp().equals(instance.getIp())) {
                    targetInstance = instance;
                    break;
                }
            }

            if (targetInstance == null) {
                log.warn("未找到运行任务的节点实例，任务ID: {}，目标IP: {}", id, entity.getIp());
                return false;
            }

            // 构造远程调用URL
            String url = "http://" + targetInstance.getIp() + ":" + targetInstance.getPort() + "/teacher/ai/task/" + id + "/stop";

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<String> entityRequest = new HttpEntity<>(headers);

            // 发起HTTP请求
            ResponseEntity<Boolean> response = restTemplate.exchange(
                    url,
                    HttpMethod.POST,
                    entityRequest,
                    Boolean.class
            );

            log.info("远程调用停止任务接口完成，任务ID: {}，响应结果: {}", id, response.getBody());
            return response.getBody();
        } catch (Exception e) {
            log.error("远程调用停止任务接口失败，任务ID: {}", id, e);
            return false;
        }
    }

    /**
     * 更新任务状态
     *
     * @param taskId 任务ID
     * @param status 新状态
     */
    private void updateTaskStatus(Integer taskId, String status,Object result) {
        AiTaskEntity entity = new AiTaskEntity();
        entity.setId(taskId);
        entity.setStatus(status);
        entity.setTaskCompletedTime(LocalDateTime.now());
        entity.setTaskResult(String.valueOf(result));
        aiTaskService.updateById(entity);
    }

    private void updateTaskStatus(Integer taskId, String status) {
        updateTaskStatus(taskId,status,null);
    }

    /**
     * 应用关闭时更新所有运行中任务的状态
     */
    @PreDestroy
    public void onDestroy() {
        log.info("应用正在关闭，开始更新所有运行中任务的状态");
        String currentIp = HostIpResolver.getHostIp();

        try {
            // 查询所有在当前节点上运行且状态为processing的任务
            LambdaQueryWrapper<AiTaskEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AiTaskEntity::getStatus, "processing");
            wrapper.eq(AiTaskEntity::getIp, currentIp);

            List<AiTaskEntity> processingTasks = aiTaskService.list(wrapper);
            log.info("找到{}个在当前节点运行的任务需要更新状态", processingTasks.size());

            // 更新所有任务状态为cancelled
            for (AiTaskEntity task : processingTasks) {
                try {
                    // 尝试取消任务
                    CompletableFuture<Void> future = taskFutures.get(task.getTaskId());
                    if (future != null && !future.isDone()) {
                        future.cancel(true);
                    }

                    // 更新任务状态
                    updateTaskStatus(task.getId(), "cancelled");
                    log.info("已更新任务[ID={}]的状态为cancelled", task.getId());

                    // 从任务映射中移除
                    taskFutures.remove(task.getTaskId());
                    stringRedisTemplate.delete(CommonConstant.TASK_CANCEL_PREFIX + task.getTaskId());
                } catch (Exception e) {
                    log.error("更新任务[ID={}]状态时发生异常", task.getId(), e);
                }
            }
        } catch (Exception e) {
            log.error("应用关闭时更新任务状态发生异常", e);
        } finally {
            log.info("应用关闭，任务状态更新完成");
        }
    }
}