package com.flowable.devops.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flowable.devops.entity.NodeType;
import com.flowable.devops.repository.NodeTypeRepository;
import com.flowable.devops.workflow.node.registry.NodeTypeRegistry;
import lombok.extern.slf4j.Slf4j;
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.*;

/**
 * 节点类型服务层
 * <p>
 * 核心功能：
 * 1. 节点类型的CRUD操作
 * 2. 节点类型元数据管理
 * 3. 节点类型注册与发现
 * 4. 输出模式管理
 */
@Slf4j
@Service
@Transactional
public class NodeTypeService {

    @Autowired
    private NodeTypeRepository nodeTypeRepository;

    @Autowired
    private NodeTypeRegistry nodeTypeRegistry;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 获取所有节点类型
     */
    @Transactional(readOnly = true)
    public List<NodeType> getAllNodeTypes() {
        return nodeTypeRepository.findAllByOrderByDisplayOrderAscIdAsc();
    }

    /**
     * 获取指定分类的节点类型
     */
    @Transactional(readOnly = true)
    public List<NodeType> getNodeTypesByCategory(String category) {
        try {
            NodeType.NodeCategory categoryEnum = NodeType.NodeCategory.valueOf(category.toUpperCase());
            return nodeTypeRepository.findByCategoryOrderByDisplayOrderAscIdAsc(categoryEnum);
        } catch (IllegalArgumentException e) {
            return new ArrayList<>();
        }
    }

    /**
     * 根据ID获取节点类型
     */
    @Transactional(readOnly = true)
    public NodeType getNodeType(String nodeTypeId) {
        return nodeTypeRepository.findById(nodeTypeId)
            .orElseThrow(() -> new NodeTypeNotFoundException("节点类型不存在: " + nodeTypeId));
    }

    /**
     * 创建节点类型
     */
    public NodeType createNodeType(NodeType nodeType) {
        log.info("创建节点类型: {}", nodeType.getId());

        try {
            // 1. 验证ID唯一性
            if (nodeTypeRepository.existsById(nodeType.getId())) {
                throw new NodeTypeServiceException("节点类型ID已存在: " + nodeType.getId());
            }

            // 2. 验证必要字段
            validateNodeType(nodeType);

            // 3. 设置创建时间
            nodeType.setCreatedAt(LocalDateTime.now());
            nodeType.setUpdatedAt(LocalDateTime.now());

            // 4. 如果没有设置显示顺序，自动分配
            if (nodeType.getDisplayOrder() == null) {
                Integer maxOrder = nodeTypeRepository.findMaxDisplayOrderByCategory(nodeType.getCategory());
                nodeType.setDisplayOrder((maxOrder != null ? maxOrder : 0) + 10);
            }

            // 5. 保存到数据库
            NodeType saved = nodeTypeRepository.save(nodeType);

            // 6. 如果节点类型启用，注册到注册表
            if (nodeType.isEnabled()) {
                registerNodeTypeToRegistry(saved);
            }

            log.info("节点类型创建成功: {}", saved.getId());
            return saved;

        } catch (Exception e) {
            log.error("创建节点类型失败: {}", nodeType.getId(), e);
            throw new NodeTypeServiceException("创建节点类型失败: " + e.getMessage(), e);
        }
    }

    /**
     * 更新节点类型
     */
    public NodeType updateNodeType(String id, NodeType nodeType) {
        log.info("更新节点类型: {}", id);

        try {
            NodeType existing = getNodeType(id);

            // 1. 更新字段
            if (nodeType.getName() != null) {
                existing.setName(nodeType.getName());
            }
            if (nodeType.getDescription() != null) {
                existing.setDescription(nodeType.getDescription());
            }
            if (nodeType.getCategory() != null) {
                existing.setCategory(nodeType.getCategory());
            }
            if (nodeType.getIcon() != null) {
                existing.setIcon(nodeType.getIcon());
            }
            if (nodeType.getFields() != null) {
                existing.setFields(nodeType.getFields());
            }
            if (nodeType.getOutputSchema() != null) {
                existing.setOutputSchema(nodeType.getOutputSchema());
            }
            if (nodeType.getDisplayOrder() != null) {
                existing.setDisplayOrder(nodeType.getDisplayOrder());
            }
            existing.setEnabled(nodeType.isEnabled());

            // 2. 验证更新后的数据
            validateNodeType(existing);

            // 3. 更新时间
            existing.setUpdatedAt(LocalDateTime.now());

            // 4. 保存更新
            NodeType updated = nodeTypeRepository.save(existing);

            // 5. 重新注册到注册表
            if (updated.isEnabled()) {
                registerNodeTypeToRegistry(updated);
            } else {
                nodeTypeRegistry.unregister(updated.getId());
            }

            log.info("节点类型更新成功: {}", id);
            return updated;

        } catch (Exception e) {
            log.error("更新节点类型失败: {}", id, e);
            throw new NodeTypeServiceException("更新节点类型失败: " + e.getMessage(), e);
        }
    }

    /**
     * 删除节点类型
     */
    public void deleteNodeType(String id) {
        log.info("删除节点类型: {}", id);

        try {
            NodeType nodeType = getNodeType(id);

            // 1. 检查是否被使用（这里可以添加业务逻辑检查）
            // TODO: 检查工作流定义中是否使用了此节点类型

            // 2. 从注册表中移除
            nodeTypeRegistry.unregister(id);

            // 3. 从数据库删除
            nodeTypeRepository.delete(nodeType);

            log.info("节点类型删除成功: {}", id);

        } catch (Exception e) {
            log.error("删除节点类型失败: {}", id, e);
            throw new NodeTypeServiceException("删除节点类型失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取节点类型分类列表
     */
    @Transactional(readOnly = true)
    public List<String> getCategories() {
        return nodeTypeRepository.findDistinctCategories();
    }

    /**
     * 刷新节点类型注册表
     * 重新加载所有启用的节点类型到注册表中
     */
    public void refreshRegistry() {
        log.info("刷新节点类型注册表");

        try {
            // 1. 清空注册表
            nodeTypeRegistry.clear();

            // 2. 先检查总数
            long totalCount = nodeTypeRepository.count();
            long enabledCount = nodeTypeRepository.countByEnabledTrue();
            log.info("数据库中总共有 {} 个节点类型，其中 {} 个启用", totalCount, enabledCount);

            // 3. 重新加载所有启用的节点类型
            List<NodeType> enabledTypes = nodeTypeRepository.findByEnabledTrueOrderByDisplayOrderAsc();
            log.info("查询返回 {} 个启用的节点类型", enabledTypes.size());

            for (NodeType nodeType : enabledTypes) {
                registerNodeTypeToRegistry(nodeType);
            }

            log.info("节点类型注册表刷新完成，已加载 {} 个节点类型", enabledTypes.size());

        } catch (Exception e) {
            log.error("刷新节点类型注册表失败", e);
            throw new NodeTypeServiceException("刷新注册表失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取节点类型输出模式
     */
    @Transactional(readOnly = true)
    public JsonNode getOutputSchema(String nodeTypeId) {
        NodeType nodeType = getNodeType(nodeTypeId);
        return nodeType.getOutputSchema();
    }

    /**
     * 更新节点类型输出模式
     */
    public NodeType updateOutputSchema(String nodeTypeId, JsonNode outputSchema) {
        log.info("更新节点类型输出模式: {}", nodeTypeId);

        try {
            NodeType nodeType = getNodeType(nodeTypeId);
            nodeType.setOutputSchema(outputSchema);
            nodeType.setUpdatedAt(LocalDateTime.now());

            NodeType updated = nodeTypeRepository.save(nodeType);

            // 重新注册到注册表
            if (updated.isEnabled()) {
                registerNodeTypeToRegistry(updated);
            }

            log.info("节点类型输出模式更新成功: {}", nodeTypeId);
            return updated;

        } catch (Exception e) {
            log.error("更新节点类型输出模式失败: {}", nodeTypeId, e);
            throw new NodeTypeServiceException("更新输出模式失败: " + e.getMessage(), e);
        }
    }

    /**
     * 启用/禁用节点类型
     */
    public NodeType toggleEnabled(String nodeTypeId, boolean enabled) {
        log.info("{}节点类型: {}", enabled ? "启用" : "禁用", nodeTypeId);

        try {
            NodeType nodeType = getNodeType(nodeTypeId);
            nodeType.setEnabled(enabled);
            nodeType.setUpdatedAt(LocalDateTime.now());

            NodeType updated = nodeTypeRepository.save(nodeType);

            // 更新注册表
            if (enabled) {
                registerNodeTypeToRegistry(updated);
            } else {
                nodeTypeRegistry.unregister(nodeTypeId);
            }

            log.info("节点类型状态更新成功: {} -> {}", nodeTypeId, enabled);
            return updated;

        } catch (Exception e) {
            log.error("更新节点类型状态失败: {}", nodeTypeId, e);
            throw new NodeTypeServiceException("更新节点类型状态失败: " + e.getMessage(), e);
        }
    }

    /**
     * 获取节点类型统计信息
     */
    @Transactional(readOnly = true)
    public NodeTypeStatistics getStatistics() {
        NodeTypeStatistics stats = new NodeTypeStatistics();

        // 总数统计
        long totalCount = nodeTypeRepository.count();
        long enabledCount = nodeTypeRepository.countByEnabledTrue();

        stats.setTotalCount(totalCount);
        stats.setEnabledCount(enabledCount);
        stats.setDisabledCount(totalCount - enabledCount);

        // 分类统计
        Map<String, Long> categoryStats = new HashMap<>();
        List<Object[]> categoryResults = nodeTypeRepository.countByCategory();
        for (Object[] result : categoryResults) {
            categoryStats.put((String) result[0], (Long) result[1]);
        }
        stats.setCategoryStats(categoryStats);

        return stats;
    }

    /**
     * 验证节点类型数据
     */
    private void validateNodeType(NodeType nodeType) {
        if (nodeType.getId() == null || nodeType.getId().trim().isEmpty()) {
            throw new NodeTypeServiceException("节点类型ID不能为空");
        }
        if (nodeType.getName() == null || nodeType.getName().trim().isEmpty()) {
            throw new NodeTypeServiceException("节点类型名称不能为空");
        }
        if (nodeType.getCategory() == null) {
            throw new NodeTypeServiceException("节点类型分类不能为空");
        }

        // 验证字段定义JSON格式
        if (nodeType.getFields() != null) {
            try {
                objectMapper.readTree(nodeType.getFields().toString());
            } catch (Exception e) {
                throw new NodeTypeServiceException("字段定义JSON格式无效: " + e.getMessage());
            }
        }

        // 验证输出模式JSON格式
        if (nodeType.getOutputSchema() != null) {
            try {
                objectMapper.readTree(nodeType.getOutputSchema().toString());
            } catch (Exception e) {
                throw new NodeTypeServiceException("输出模式JSON格式无效: " + e.getMessage());
            }
        }
    }

    /**
     * 将节点类型注册到注册表
     */
    private void registerNodeTypeToRegistry(NodeType nodeType) {
        try {
            nodeTypeRegistry.registerFromDatabase(nodeType);
            log.debug("节点类型已注册到注册表: {}", nodeType.getId());
        } catch (Exception e) {
            log.warn("注册节点类型到注册表失败: {} - {}", nodeType.getId(), e.getMessage());
        }
    }

    /**
     * 节点类型统计信息
     */
    public static class NodeTypeStatistics {
        private long totalCount;

        private long enabledCount;

        private long disabledCount;

        private Map<String, Long> categoryStats;

        // Getters and Setters
        public long getTotalCount() {
            return totalCount;
        }

        public void setTotalCount(long totalCount) {
            this.totalCount = totalCount;
        }

        public long getEnabledCount() {
            return enabledCount;
        }

        public void setEnabledCount(long enabledCount) {
            this.enabledCount = enabledCount;
        }

        public long getDisabledCount() {
            return disabledCount;
        }

        public void setDisabledCount(long disabledCount) {
            this.disabledCount = disabledCount;
        }

        public Map<String, Long> getCategoryStats() {
            return categoryStats;
        }

        public void setCategoryStats(Map<String, Long> categoryStats) {
            this.categoryStats = categoryStats;
        }
    }
}