package com.flowable.devops.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flowable.devops.entity.WorkflowDefinition;
import com.flowable.devops.entity.WorkflowExecution;
import com.flowable.devops.repository.WorkflowDefinitionRepository;
import com.flowable.devops.repository.WorkflowExecutionRepository;
import com.flowable.devops.workflow.converter.WorkflowConverter;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 工作流服务层
 * 
 * 核心业务功能：
 * 1. 工作流定义的CRUD操作
 * 2. JSON转BPMN并部署到Flowable
 * 3. 工作流执行和监控
 * 4. 执行历史查询
 */
@Slf4j
@Service
@Transactional
public class WorkflowService {
    
    @Autowired
    private WorkflowDefinitionRepository workflowDefinitionRepository;
    
    @Autowired
    private WorkflowExecutionRepository workflowExecutionRepository;
    
    @Autowired
    private WorkflowConverter workflowConverter;
    
    @Autowired
    private ProcessEngine processEngine;
    
    @Autowired
    private RepositoryService repositoryService;
    
    @Autowired
    private RuntimeService runtimeService;
    
    private final ObjectMapper objectMapper = new ObjectMapper();
    
    /**
     * 创建工作流定义
     */
    @Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRES_NEW)
    public WorkflowDefinition create(WorkflowDefinition workflow) {
        log.info("创建工作流定义: {}", workflow.getName());
        
        try {
            // 1. 生成ID（如果没有）
            if (workflow.getId() == null || workflow.getId().trim().isEmpty()) {
                workflow.setId("workflow_" + UUID.randomUUID().toString().replace("-", ""));
            }
            
            // 2. 验证工作流JSON（添加null检查）
            JsonNode workflowJson = workflow.getDefinition();
            if (workflowJson != null) {
                workflowConverter.validateWorkflowJson(workflowJson);
                workflowConverter.validateWorkflowTopology(workflowJson);
            }
            
            // 3. 设置基本信息
            workflow.setStatus(WorkflowDefinition.WorkflowStatus.DRAFT);
            workflow.setCreatedBy("system"); // TODO: 从安全上下文获取当前用户
            
            // 4. 保存到数据库
            WorkflowDefinition saved = workflowDefinitionRepository.save(workflow);
            
            // 5. 强制刷新到数据库
            workflowDefinitionRepository.flush();
            
            log.info("工作流定义创建成功: {} (ID: {})", workflow.getName(), saved.getId());
            return saved;
            
        } catch (Exception e) {
            log.error("创建工作流定义失败: {}", workflow.getName(), e);
            throw new WorkflowServiceException("创建工作流定义失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 更新工作流定义
     */
    public WorkflowDefinition update(String id, WorkflowDefinition workflow) {
        log.info("更新工作流定义: {}", id);
        
        try {
            // 1. 检查是否存在
            WorkflowDefinition existing = getById(id);
            
            // 2. 验证工作流JSON
            if (workflow.getDefinition() != null) {
                workflowConverter.validateWorkflowJson(workflow.getDefinition());
                workflowConverter.validateWorkflowTopology(workflow.getDefinition());
                existing.setDefinition(workflow.getDefinition());
            }
            
            // 3. 更新字段
            if (workflow.getName() != null) {
                existing.setName(workflow.getName());
            }
            if (workflow.getDescription() != null) {
                existing.setDescription(workflow.getDescription());
            }
            
            // 4. 如果已激活，需要重新部署
            if (existing.getStatus() == WorkflowDefinition.WorkflowStatus.ACTIVE) {
                log.info("工作流已激活，将重新部署: {}", id);
                deployToFlowable(existing);
            }
            
            // 5. 保存更新
            WorkflowDefinition updated = workflowDefinitionRepository.save(existing);
            
            log.info("工作流定义更新成功: {}", id);
            return updated;
            
        } catch (Exception e) {
            log.error("更新工作流定义失败: {}", id, e);
            throw new WorkflowServiceException("更新工作流定义失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取工作流定义
     */
    @Transactional(readOnly = true)
    public WorkflowDefinition getById(String id) {
        return workflowDefinitionRepository.findById(id)
                .orElseThrow(() -> new WorkflowNotFoundException("工作流定义不存在: " + id));
    }
    
    /**
     * 获取工作流列表
     */
    @Transactional(readOnly = true)
    public List<WorkflowDefinition> list(String status) {
        if (status != null) {
            try {
                WorkflowDefinition.WorkflowStatus workflowStatus = 
                    WorkflowDefinition.WorkflowStatus.valueOf(status.toUpperCase());
                return workflowDefinitionRepository.findByStatus(workflowStatus);
            } catch (IllegalArgumentException e) {
                log.warn("无效的工作流状态: {}", status);
            }
        }
        
        return workflowDefinitionRepository.findAll();
    }
    
    /**
     * 删除工作流定义
     */
    public void delete(String id) {
        log.info("删除工作流定义: {}", id);
        
        try {
            WorkflowDefinition workflow = getById(id);
            
            // 1. 检查是否有正在运行的实例
            long runningCount = workflowExecutionRepository.countByWorkflowDefinitionId(id);
            if (runningCount > 0) {
                throw new WorkflowServiceException("无法删除工作流，存在正在执行的实例: " + runningCount);
            }
            
            // 2. 从Flowable中删除流程定义
            if (workflow.getFlowableProcessDefinitionId() != null) {
                try {
                    repositoryService.deleteDeployment(workflow.getFlowableDeploymentId(), true);
                    log.info("已从Flowable删除流程定义: {}", workflow.getFlowableProcessDefinitionId());
                } catch (Exception e) {
                    log.warn("从Flowable删除流程定义失败: {}", e.getMessage());
                }
            }
            
            // 3. 删除数据库记录
            workflowDefinitionRepository.delete(workflow);
            
            log.info("工作流定义删除成功: {}", id);
            
        } catch (Exception e) {
            log.error("删除工作流定义失败: {}", id, e);
            throw new WorkflowServiceException("删除工作流定义失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 激活工作流（部署到Flowable）
     */
    public WorkflowDefinition activate(String id) {
        log.info("激活工作流定义: {}", id);
        
        try {
            WorkflowDefinition workflow = getById(id);
            
            // 1. 部署到Flowable
            deployToFlowable(workflow);
            
            // 2. 更新状态
            workflow.setStatus(WorkflowDefinition.WorkflowStatus.ACTIVE);
            WorkflowDefinition activated = workflowDefinitionRepository.save(workflow);
            
            log.info("工作流定义激活成功: {} -> {}", id, workflow.getFlowableProcessDefinitionId());
            return activated;
            
        } catch (Exception e) {
            log.error("激活工作流定义失败: {}", id, e);
            throw new WorkflowServiceException("激活工作流定义失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 部署工作流到Flowable
     */
    private void deployToFlowable(WorkflowDefinition workflow) {
        try {
            // 1. 转换JSON到BPMN
            String bpmnXml = workflowConverter.convertToBpmn(workflow.getDefinition());
            
            // 2. 部署到Flowable
            String deploymentName = workflow.getName() + "_v" + System.currentTimeMillis();
            String resourceName = workflow.getId() + ".bpmn20.xml";
            
            Deployment deployment = repositoryService.createDeployment()
                    .name(deploymentName)
                    .addString(resourceName, bpmnXml)
                    .deploy();
            
            // 3. 获取流程定义
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                    .deploymentId(deployment.getId())
                    .singleResult();
            
            // 4. 更新工作流信息
            workflow.setFlowableDeploymentId(deployment.getId());
            workflow.setFlowableProcessDefinitionId(processDefinition.getId());
            
            log.info("工作流部署成功: {} -> {} (deployment: {})", 
                    workflow.getName(), processDefinition.getId(), deployment.getId());
            
        } catch (Exception e) {
            log.error("部署工作流到Flowable失败: {}", workflow.getId(), e);
            throw new WorkflowServiceException("部署工作流失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 执行工作流
     */
    public WorkflowExecutionResult execute(String id, Map<String, Object> input) {
        log.info("开始执行工作流: {} (输入: {})", id, input);
        
        try {
            WorkflowDefinition workflow = getById(id);
            
            // 1. 检查状态
            if (workflow.getStatus() != WorkflowDefinition.WorkflowStatus.ACTIVE) {
                throw new WorkflowServiceException("工作流未激活，无法执行: " + workflow.getStatus());
            }
            
            // 2. 创建执行记录
            WorkflowExecution execution = new WorkflowExecution();
            execution.setWorkflowDefinitionId(id);
            execution.setInput(objectMapper.valueToTree(input));
            execution.setStatus(WorkflowExecution.ExecutionStatus.RUNNING);
            execution.setTriggerType(WorkflowExecution.TriggerType.MANUAL);
            execution.setTriggeredBy("system"); // TODO: 从安全上下文获取
            execution = workflowExecutionRepository.save(execution);
            
            // 3. 准备流程变量
            Map<String, Object> variables = new HashMap<>();
            variables.put("workflow", Map.of("input", input, "executionId", execution.getId()));
            variables.put("nodes", new HashMap<>()); // 节点输出容器
            
            // 4. 启动流程实例
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(
                    workflow.getFlowableProcessDefinitionId(),
                    execution.getId(),
                    variables
            );
            
            // 5. 更新执行记录
            execution.setFlowableProcessInstanceId(processInstance.getId());
            
            // 6. 检查执行状态
            boolean isCompleted = processInstance.isEnded();
            if (isCompleted) {
                execution.setStatus(WorkflowExecution.ExecutionStatus.COMPLETED);
                execution.setEndedAt(LocalDateTime.now());
            }
            
            execution = workflowExecutionRepository.save(execution);
            
            // 7. 构建返回结果
            WorkflowExecutionResult result = buildExecutionResult(execution, processInstance, variables);
            
            log.info("工作流执行完成: {} -> {} (状态: {})", 
                    id, processInstance.getId(), result.getStatus());
            
            return result;
            
        } catch (Exception e) {
            log.error("执行工作流失败: {}", id, e);
            throw new WorkflowServiceException("执行工作流失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 构建执行结果
     */
    @SuppressWarnings("unchecked")
    private WorkflowExecutionResult buildExecutionResult(
            WorkflowExecution execution,
            ProcessInstance processInstance,
            Map<String, Object> variables
    ) {
        WorkflowExecutionResult result = new WorkflowExecutionResult();
        result.setWorkflowId(execution.getWorkflowDefinitionId());
        result.setProcessInstanceId(processInstance.getId());
        result.setExecutionId(execution.getId());
        result.setStartedAt(execution.getStartedAt());
        result.setEndedAt(execution.getEndedAt());
        
        // 设置状态
        if (processInstance.isEnded()) {
            result.setStatus("completed");
        } else {
            result.setStatus("running");
        }
        
        // 获取节点执行数据
        Map<String, Object> nodesData = (Map<String, Object>) variables.get("nodes");
        if (nodesData != null) {
            result.setNodes(nodesData);
        }
        
        // 获取输出数据（从最后一个节点）
        if (nodesData != null && processInstance.isEnded()) {
            // 简化实现：返回所有节点输出
            Map<String, Object> output = new HashMap<>();
            nodesData.forEach((nodeId, nodeData) -> {
                if (nodeData instanceof Map) {
                    Map<String, Object> nodeMap = (Map<String, Object>) nodeData;
                    Object nodeOutput = nodeMap.get("output");
                    if (nodeOutput != null) {
                        output.put(nodeId, nodeOutput);
                    }
                }
            });
            result.setOutput(output);
        }
        
        return result;
    }
    
    /**
     * 获取执行历史
     */
    @Transactional(readOnly = true)
    public List<WorkflowExecution> getExecutions(String workflowId) {
        return workflowExecutionRepository.findByWorkflowDefinitionIdOrderByStartedAtDesc(workflowId);
    }
    
    /**
     * 获取执行详情
     */
    @Transactional(readOnly = true)
    public WorkflowExecutionDetail getExecutionDetail(String executionId) {
        WorkflowExecution execution = workflowExecutionRepository.findById(executionId)
                .orElseThrow(() -> new WorkflowNotFoundException("执行记录不存在: " + executionId));
        
        WorkflowExecutionDetail detail = new WorkflowExecutionDetail();
        detail.setId(execution.getId());
        detail.setWorkflowDefinitionId(execution.getWorkflowDefinitionId());
        detail.setProcessInstanceId(execution.getFlowableProcessInstanceId());
        detail.setStatus(execution.getStatus().name().toLowerCase());
        detail.setInput(execution.getInput());
        detail.setStartedAt(execution.getStartedAt());
        detail.setEndedAt(execution.getEndedAt());
        detail.setError(execution.getErrorMessage());
        
        // TODO: 从流程变量或日志表获取节点执行详情
        detail.setNodes(new HashMap<>());
        
        return detail;
    }
    
    /**
     * 工作流执行结果
     */
    public static class WorkflowExecutionResult {
        private String workflowId;
        private String processInstanceId;
        private String executionId;
        private String status;
        private Map<String, Object> output;
        private Map<String, Object> nodes;
        private LocalDateTime startedAt;
        private LocalDateTime endedAt;
        
        // Getters and Setters
        public String getWorkflowId() { return workflowId; }
        public void setWorkflowId(String workflowId) { this.workflowId = workflowId; }
        
        public String getProcessInstanceId() { return processInstanceId; }
        public void setProcessInstanceId(String processInstanceId) { this.processInstanceId = processInstanceId; }
        
        public String getExecutionId() { return executionId; }
        public void setExecutionId(String executionId) { this.executionId = executionId; }
        
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
        
        public Map<String, Object> getOutput() { return output; }
        public void setOutput(Map<String, Object> output) { this.output = output; }
        
        public Map<String, Object> getNodes() { return nodes; }
        public void setNodes(Map<String, Object> nodes) { this.nodes = nodes; }
        
        public LocalDateTime getStartedAt() { return startedAt; }
        public void setStartedAt(LocalDateTime startedAt) { this.startedAt = startedAt; }
        
        public LocalDateTime getEndedAt() { return endedAt; }
        public void setEndedAt(LocalDateTime endedAt) { this.endedAt = endedAt; }
    }
    
    /**
     * 工作流执行详情
     */
    public static class WorkflowExecutionDetail {
        private String id;
        private String workflowDefinitionId;
        private String processInstanceId;
        private String status;
        private JsonNode input;
        private Map<String, Object> nodes;
        private LocalDateTime startedAt;
        private LocalDateTime endedAt;
        private String error;
        
        // Getters and Setters
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        
        public String getWorkflowDefinitionId() { return workflowDefinitionId; }
        public void setWorkflowDefinitionId(String workflowDefinitionId) { this.workflowDefinitionId = workflowDefinitionId; }
        
        public String getProcessInstanceId() { return processInstanceId; }
        public void setProcessInstanceId(String processInstanceId) { this.processInstanceId = processInstanceId; }
        
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
        
        public JsonNode getInput() { return input; }
        public void setInput(JsonNode input) { this.input = input; }
        
        public Map<String, Object> getNodes() { return nodes; }
        public void setNodes(Map<String, Object> nodes) { this.nodes = nodes; }
        
        public LocalDateTime getStartedAt() { return startedAt; }
        public void setStartedAt(LocalDateTime startedAt) { this.startedAt = startedAt; }
        
        public LocalDateTime getEndedAt() { return endedAt; }
        public void setEndedAt(LocalDateTime endedAt) { this.endedAt = endedAt; }
        
        public String getError() { return error; }
        public void setError(String error) { this.error = error; }
    }
}