package com.flowable.devops.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 任务服务层
 * 
 * 核心功能：
 * 1. 用户任务查询和管理
 * 2. 任务完成和审批处理
 * 3. 任务委派和转办
 * 4. 任务历史查询
 */
@Slf4j
@Service
@Transactional
public class TaskService {
    
    @Autowired
    private org.flowable.engine.TaskService flowableTaskService;
    
    @Autowired
    private RuntimeService runtimeService;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 获取用户待办任务
     */
    @Transactional(readOnly = true)
    public List<TaskInfo> getTasks(String assignee) {
        log.info("获取用户待办任务: {}", assignee);
        
        TaskQuery query = flowableTaskService.createTaskQuery()
                .taskAssignee(assignee)
                .orderByTaskCreateTime()
                .desc();
        
        List<Task> tasks = query.list();
        return tasks.stream()
                .map(this::convertToTaskInfo)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取用户候选任务
     */
    @Transactional(readOnly = true)
    public List<TaskInfo> getCandidateTasks(String userId, List<String> groups) {
        log.info("获取用户候选任务: {} (组: {})", userId, groups);
        
        TaskQuery query = flowableTaskService.createTaskQuery()
                .taskCandidateUser(userId)
                .orderByTaskCreateTime()
                .desc();
        
        // 添加候选组条件
        if (groups != null && !groups.isEmpty()) {
            query = query.taskCandidateGroupIn(groups);
        }
        
        List<Task> tasks = query.list();
        return tasks.stream()
                .map(this::convertToTaskInfo)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取任务详情
     */
    @Transactional(readOnly = true)
    public TaskDetail getTaskDetail(String taskId) {
        log.info("获取任务详情: {}", taskId);
        
        Task task = flowableTaskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
        
        if (task == null) {
            throw new TaskNotFoundException("任务不存在: " + taskId);
        }
        
        TaskDetail detail = new TaskDetail();
        detail.setId(task.getId());
        detail.setName(task.getName());
        detail.setDescription(task.getDescription());
        detail.setAssignee(task.getAssignee());
        detail.setOwner(task.getOwner());
        detail.setProcessInstanceId(task.getProcessInstanceId());
        detail.setProcessDefinitionId(task.getProcessDefinitionId());
        detail.setTaskDefinitionKey(task.getTaskDefinitionKey());
        detail.setPriority(task.getPriority());
        detail.setDueDate(task.getDueDate() != null ? 
                task.getDueDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() : null);
        detail.setCreateTime(task.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        
        // 获取任务变量
        Map<String, Object> variables = flowableTaskService.getVariables(taskId);
        detail.setVariables(variables);
        
        // 获取表单数据（如果存在）
        if (task.getFormKey() != null) {
            detail.setFormKey(task.getFormKey());
            // TODO: 根据formKey获取具体的表单数据
        }
        
        return detail;
    }
    
    /**
     * 完成任务
     */
    public void completeTask(String taskId, String userId, Map<String, Object> variables, String comment) {
        log.info("完成任务: {} (用户: {}, 评论: {})", taskId, userId, comment);
        
        try {
            // 1. 验证任务存在且可以被当前用户完成
            Task task = flowableTaskService.createTaskQuery()
                    .taskId(taskId)
                    .singleResult();
            
            if (task == null) {
                throw new TaskNotFoundException("任务不存在: " + taskId);
            }
            
            // 2. 检查任务分配情况
            if (task.getAssignee() == null) {
                // 如果任务未分配，先认领任务
                flowableTaskService.claim(taskId, userId);
                log.info("用户 {} 认领任务: {}", userId, taskId);
            } else if (!task.getAssignee().equals(userId)) {
                throw new TaskServiceException("用户无权完成此任务: " + taskId);
            }
            
            // 3. 添加评论（如果有）
            if (comment != null && !comment.trim().isEmpty()) {
                flowableTaskService.addComment(taskId, task.getProcessInstanceId(), comment);
            }
            
            // 4. 完成任务
            if (variables != null && !variables.isEmpty()) {
                flowableTaskService.complete(taskId, variables);
            } else {
                flowableTaskService.complete(taskId);
            }
            
            log.info("任务完成成功: {} (用户: {})", taskId, userId);
            
        } catch (Exception e) {
            log.error("完成任务失败: {} (用户: {})", taskId, userId, e);
            throw new TaskServiceException("完成任务失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 认领任务
     */
    public void claimTask(String taskId, String userId) {
        log.info("认领任务: {} (用户: {})", taskId, userId);
        
        try {
            Task task = flowableTaskService.createTaskQuery()
                    .taskId(taskId)
                    .singleResult();
            
            if (task == null) {
                throw new TaskNotFoundException("任务不存在: " + taskId);
            }
            
            if (task.getAssignee() != null) {
                throw new TaskServiceException("任务已被分配: " + task.getAssignee());
            }
            
            flowableTaskService.claim(taskId, userId);
            log.info("任务认领成功: {} -> {}", taskId, userId);
            
        } catch (Exception e) {
            log.error("认领任务失败: {} (用户: {})", taskId, userId, e);
            throw new TaskServiceException("认领任务失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 释放任务（取消认领）
     */
    public void unclaimTask(String taskId, String userId) {
        log.info("释放任务: {} (用户: {})", taskId, userId);
        
        try {
            Task task = flowableTaskService.createTaskQuery()
                    .taskId(taskId)
                    .taskAssignee(userId)
                    .singleResult();
            
            if (task == null) {
                throw new TaskNotFoundException("任务不存在或不属于当前用户: " + taskId);
            }
            
            flowableTaskService.unclaim(taskId);
            log.info("任务释放成功: {}", taskId);
            
        } catch (Exception e) {
            log.error("释放任务失败: {} (用户: {})", taskId, userId, e);
            throw new TaskServiceException("释放任务失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 委派任务
     */
    public void delegateTask(String taskId, String fromUserId, String toUserId, String comment) {
        log.info("委派任务: {} (从 {} 到 {}, 评论: {})", taskId, fromUserId, toUserId, comment);
        
        try {
            Task task = flowableTaskService.createTaskQuery()
                    .taskId(taskId)
                    .taskAssignee(fromUserId)
                    .singleResult();
            
            if (task == null) {
                throw new TaskNotFoundException("任务不存在或不属于当前用户: " + taskId);
            }
            
            // 添加委派评论
            if (comment != null && !comment.trim().isEmpty()) {
                flowableTaskService.addComment(taskId, task.getProcessInstanceId(), comment);
            }
            
            // 执行委派
            flowableTaskService.delegateTask(taskId, toUserId);
            log.info("任务委派成功: {} -> {}", taskId, toUserId);
            
        } catch (Exception e) {
            log.error("委派任务失败: {} (从 {} 到 {})", taskId, fromUserId, toUserId, e);
            throw new TaskServiceException("委派任务失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 转办任务
     */
    public void transferTask(String taskId, String fromUserId, String toUserId, String comment) {
        log.info("转办任务: {} (从 {} 到 {}, 评论: {})", taskId, fromUserId, toUserId, comment);
        
        try {
            Task task = flowableTaskService.createTaskQuery()
                    .taskId(taskId)
                    .taskAssignee(fromUserId)
                    .singleResult();
            
            if (task == null) {
                throw new TaskNotFoundException("任务不存在或不属于当前用户: " + taskId);
            }
            
            // 添加转办评论
            if (comment != null && !comment.trim().isEmpty()) {
                flowableTaskService.addComment(taskId, task.getProcessInstanceId(), comment);
            }
            
            // 执行转办（重新分配）
            flowableTaskService.setAssignee(taskId, toUserId);
            log.info("任务转办成功: {} -> {}", taskId, toUserId);
            
        } catch (Exception e) {
            log.error("转办任务失败: {} (从 {} 到 {})", taskId, fromUserId, toUserId, e);
            throw new TaskServiceException("转办任务失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取任务评论
     */
    @Transactional(readOnly = true)
    public List<TaskComment> getTaskComments(String taskId) {
        log.info("获取任务评论: {}", taskId);
        
        Task task = flowableTaskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
        
        if (task == null) {
            throw new TaskNotFoundException("任务不存在: " + taskId);
        }
        
        List<org.flowable.engine.task.Comment> comments = flowableTaskService.getTaskComments(taskId);
        return comments.stream()
                .map(this::convertToTaskComment)
                .collect(Collectors.toList());
    }
    
    /**
     * 添加任务评论
     */
    public TaskComment addTaskComment(String taskId, String userId, String message) {
        log.info("添加任务评论: {} (用户: {}, 内容: {})", taskId, userId, message);
        
        try {
            Task task = flowableTaskService.createTaskQuery()
                    .taskId(taskId)
                    .singleResult();
            
            if (task == null) {
                throw new TaskNotFoundException("任务不存在: " + taskId);
            }
            
            org.flowable.engine.task.Comment comment = flowableTaskService.addComment(
                    taskId, task.getProcessInstanceId(), message);
            
            log.info("任务评论添加成功: {} (ID: {})", taskId, comment.getId());
            return convertToTaskComment(comment);
            
        } catch (Exception e) {
            log.error("添加任务评论失败: {} (用户: {})", taskId, userId, e);
            throw new TaskServiceException("添加任务评论失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取任务统计信息
     */
    @Transactional(readOnly = true)
    public TaskStatistics getTaskStatistics(String userId, List<String> groups) {
        TaskStatistics stats = new TaskStatistics();
        
        // 待办任务数量
        long assignedCount = flowableTaskService.createTaskQuery()
                .taskAssignee(userId)
                .count();
        stats.setAssignedCount(assignedCount);
        
        // 候选任务数量
        TaskQuery candidateQuery = flowableTaskService.createTaskQuery()
                .taskCandidateUser(userId);
        
        if (groups != null && !groups.isEmpty()) {
            candidateQuery = candidateQuery.taskCandidateGroupIn(groups);
        }
        
        long candidateCount = candidateQuery.count();
        stats.setCandidateCount(candidateCount);
        
        // 逾期任务数量
        long overdueCount = flowableTaskService.createTaskQuery()
                .taskAssignee(userId)
                .taskDueBefore(new Date())
                .count();
        stats.setOverdueCount(overdueCount);
        
        return stats;
    }
    
    /**
     * 转换Task为TaskInfo
     */
    private TaskInfo convertToTaskInfo(Task task) {
        TaskInfo info = new TaskInfo();
        info.setId(task.getId());
        info.setName(task.getName());
        info.setDescription(task.getDescription());
        info.setAssignee(task.getAssignee());
        info.setOwner(task.getOwner());
        info.setProcessInstanceId(task.getProcessInstanceId());
        info.setProcessDefinitionId(task.getProcessDefinitionId());
        info.setTaskDefinitionKey(task.getTaskDefinitionKey());
        info.setPriority(task.getPriority());
        info.setCreateTime(task.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        
        if (task.getDueDate() != null) {
            info.setDueDate(task.getDueDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        }
        
        // 判断是否逾期
        if (task.getDueDate() != null && task.getDueDate().before(new Date())) {
            info.setOverdue(true);
        }
        
        return info;
    }
    
    /**
     * 转换Comment为TaskComment
     */
    private TaskComment convertToTaskComment(org.flowable.engine.task.Comment comment) {
        TaskComment taskComment = new TaskComment();
        taskComment.setId(comment.getId());
        taskComment.setUserId(comment.getUserId());
        taskComment.setMessage(comment.getFullMessage());
        taskComment.setTime(comment.getTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
        return taskComment;
    }
    
    /**
     * 任务信息
     */
    public static class TaskInfo {
        private String id;
        private String name;
        private String description;
        private String assignee;
        private String owner;
        private String processInstanceId;
        private String processDefinitionId;
        private String taskDefinitionKey;
        private Integer priority;
        private LocalDateTime createTime;
        private LocalDateTime dueDate;
        private boolean overdue;
        
        // Getters and Setters
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        
        public String getAssignee() { return assignee; }
        public void setAssignee(String assignee) { this.assignee = assignee; }
        
        public String getOwner() { return owner; }
        public void setOwner(String owner) { this.owner = owner; }
        
        public String getProcessInstanceId() { return processInstanceId; }
        public void setProcessInstanceId(String processInstanceId) { this.processInstanceId = processInstanceId; }
        
        public String getProcessDefinitionId() { return processDefinitionId; }
        public void setProcessDefinitionId(String processDefinitionId) { this.processDefinitionId = processDefinitionId; }
        
        public String getTaskDefinitionKey() { return taskDefinitionKey; }
        public void setTaskDefinitionKey(String taskDefinitionKey) { this.taskDefinitionKey = taskDefinitionKey; }
        
        public Integer getPriority() { return priority; }
        public void setPriority(Integer priority) { this.priority = priority; }
        
        public LocalDateTime getCreateTime() { return createTime; }
        public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
        
        public LocalDateTime getDueDate() { return dueDate; }
        public void setDueDate(LocalDateTime dueDate) { this.dueDate = dueDate; }
        
        public boolean isOverdue() { return overdue; }
        public void setOverdue(boolean overdue) { this.overdue = overdue; }
    }
    
    /**
     * 任务详情
     */
    public static class TaskDetail {
        private String id;
        private String name;
        private String description;
        private String assignee;
        private String owner;
        private String processInstanceId;
        private String processDefinitionId;
        private String taskDefinitionKey;
        private String formKey;
        private Integer priority;
        private LocalDateTime createTime;
        private LocalDateTime dueDate;
        private Map<String, Object> variables;
        
        // Getters and Setters
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        
        public String getAssignee() { return assignee; }
        public void setAssignee(String assignee) { this.assignee = assignee; }
        
        public String getOwner() { return owner; }
        public void setOwner(String owner) { this.owner = owner; }
        
        public String getProcessInstanceId() { return processInstanceId; }
        public void setProcessInstanceId(String processInstanceId) { this.processInstanceId = processInstanceId; }
        
        public String getProcessDefinitionId() { return processDefinitionId; }
        public void setProcessDefinitionId(String processDefinitionId) { this.processDefinitionId = processDefinitionId; }
        
        public String getTaskDefinitionKey() { return taskDefinitionKey; }
        public void setTaskDefinitionKey(String taskDefinitionKey) { this.taskDefinitionKey = taskDefinitionKey; }
        
        public String getFormKey() { return formKey; }
        public void setFormKey(String formKey) { this.formKey = formKey; }
        
        public Integer getPriority() { return priority; }
        public void setPriority(Integer priority) { this.priority = priority; }
        
        public LocalDateTime getCreateTime() { return createTime; }
        public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
        
        public LocalDateTime getDueDate() { return dueDate; }
        public void setDueDate(LocalDateTime dueDate) { this.dueDate = dueDate; }
        
        public Map<String, Object> getVariables() { return variables; }
        public void setVariables(Map<String, Object> variables) { this.variables = variables; }
    }
    
    /**
     * 任务评论
     */
    public static class TaskComment {
        private String id;
        private String userId;
        private String message;
        private LocalDateTime time;
        
        // Getters and Setters
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        
        public String getUserId() { return userId; }
        public void setUserId(String userId) { this.userId = userId; }
        
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        
        public LocalDateTime getTime() { return time; }
        public void setTime(LocalDateTime time) { this.time = time; }
    }
    
    /**
     * 任务统计信息
     */
    public static class TaskStatistics {
        private long assignedCount;
        private long candidateCount;
        private long overdueCount;
        
        // Getters and Setters
        public long getAssignedCount() { return assignedCount; }
        public void setAssignedCount(long assignedCount) { this.assignedCount = assignedCount; }
        
        public long getCandidateCount() { return candidateCount; }
        public void setCandidateCount(long candidateCount) { this.candidateCount = candidateCount; }
        
        public long getOverdueCount() { return overdueCount; }
        public void setOverdueCount(long overdueCount) { this.overdueCount = overdueCount; }
    }
}
