package com.yhy.module.core.service.workbench.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import com.yhy.module.core.controller.admin.workbench.vo.WbResourceSourceBoqRespVO;
import com.yhy.module.core.controller.admin.workbench.vo.WbResourceSourceUnitRespVO;
import com.yhy.module.core.controller.admin.workbench.vo.WbResourceSummaryRespVO;
import com.yhy.module.core.controller.admin.workbench.vo.WbResourceSummaryTreeRespVO;
import com.yhy.module.core.controller.admin.workbench.vo.WbResourceSummaryUpdateReqVO;
import com.yhy.module.core.dal.dataobject.workbench.WbBoqDivisionDO;
import com.yhy.module.core.dal.dataobject.workbench.WbBoqResourceDO;
import com.yhy.module.core.dal.dataobject.workbench.WbCompileTreeDO;
import com.yhy.module.core.dal.dataobject.workbench.WbResourceSummaryDO;
import com.yhy.module.core.dal.mysql.workbench.WbBoqDivisionMapper;
import com.yhy.module.core.dal.mysql.workbench.WbBoqResourceMapper;
import com.yhy.module.core.dal.mysql.workbench.WbCompileTreeMapper;
import com.yhy.module.core.dal.mysql.workbench.WbResourceSummaryMapper;
import com.yhy.module.core.service.workbench.WbResourceSummaryService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

/**
 * 工料机汇总 Service 实现类
 *
 * @author yhy
 */
@Service
@Validated
@Slf4j
public class WbResourceSummaryServiceImpl implements WbResourceSummaryService {

    @Resource
    private WbResourceSummaryMapper wbResourceSummaryMapper;

    @Resource
    private WbBoqResourceMapper wbBoqResourceMapper;

    @Resource
    private WbBoqDivisionMapper wbBoqDivisionMapper;

    @Resource
    private WbCompileTreeMapper wbCompileTreeMapper;

    @Override
    public List<WbResourceSummaryTreeRespVO> getSummaryTree(Long projectId, Long compileTreeId) {
        // 1. 查询工料机汇总数据（支持单位工程级过滤）
        List<ResourceAggregation> aggregations = getResourceAggregations(projectId, null, compileTreeId);
        
        // 2. 查询评标指定材料数量
        List<WbResourceSummaryDO> bidMaterials = wbResourceSummaryMapper.selectBidMaterialsByProjectId(projectId);
        
        // 3. 按工料机类别（resource_type）动态统计数量
        Map<String, Integer> categoryCount = new LinkedHashMap<>();
        for (ResourceAggregation agg : aggregations) {
            String type = agg.getResourceType();
            if (type != null) {
                categoryCount.merge(type, 1, Integer::sum);
            }
        }
        
        // 4. 动态构建类别子节点
        List<WbResourceSummaryTreeRespVO> children = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : categoryCount.entrySet()) {
            WbResourceSummaryTreeRespVO node = new WbResourceSummaryTreeRespVO();
            node.setId(entry.getKey());
            node.setName(entry.getKey());
            node.setNodeType(WbResourceSummaryTreeRespVO.NODE_TYPE_CATEGORY);
            node.setResourceType(entry.getKey());
            node.setCount(entry.getValue());
            children.add(node);
        }
        
        // 评标指定材料
        WbResourceSummaryTreeRespVO bidMaterialNode = new WbResourceSummaryTreeRespVO();
        bidMaterialNode.setId("bid_material");
        bidMaterialNode.setName("评标指定材料");
        bidMaterialNode.setNodeType(WbResourceSummaryTreeRespVO.NODE_TYPE_BID_MATERIAL);
        bidMaterialNode.setCount(bidMaterials.size());
        children.add(bidMaterialNode);
        
        // 根节点
        WbResourceSummaryTreeRespVO root = new WbResourceSummaryTreeRespVO();
        root.setId("root");
        root.setName("工料机汇总");
        root.setNodeType(WbResourceSummaryTreeRespVO.NODE_TYPE_ROOT);
        root.setCount(aggregations.size());
        root.setChildren(children);
        
        List<WbResourceSummaryTreeRespVO> result = new ArrayList<>();
        result.add(root);
        return result;
    }

    @Override
    public List<WbResourceSummaryRespVO> getSummaryList(Long projectId, String category, Long compileTreeId) {
        // 1. 查询汇总数据（支持单位工程级过滤）
        List<ResourceAggregation> aggregations;
        if ("bid_material".equals(category)) {
            // 评标指定材料：只返回标记为评标指定材料的
            aggregations = getBidMaterialAggregations(projectId);
        } else {
            // 按类别查询（category 直接就是 resource_type 值，如"人"/"材"/"机"）
            aggregations = getResourceAggregations(projectId, category, compileTreeId);
        }
        
        // 2. 查询用户标记
        List<WbResourceSummaryDO> summaries = wbResourceSummaryMapper.selectListByProjectId(projectId);
        Map<String, WbResourceSummaryDO> summaryMap = summaries.stream()
                .collect(Collectors.toMap(WbResourceSummaryDO::getResourceKey, s -> s, (a, b) -> a));
        
        // 3. 转换为VO
        return aggregations.stream().map(agg -> {
            WbResourceSummaryRespVO vo = new WbResourceSummaryRespVO();
            vo.setResourceKey(agg.getResourceKey());
            vo.setCode(agg.getCode());
            vo.setName(agg.getName());
            vo.setSpec(agg.getSpec());
            vo.setUnit(agg.getUnit());
            vo.setResourceType(agg.getResourceType());
            vo.setTaxRate(agg.getTaxRate());
            vo.setTotalQty(agg.getTotalQty());
            vo.setTaxExclBasePrice(agg.getTaxExclBasePrice());
            vo.setTaxInclBasePrice(agg.getTaxInclBasePrice());
            vo.setTaxExclCompilePrice(agg.getTaxExclCompilePrice());
            vo.setTaxInclCompilePrice(agg.getTaxInclCompilePrice());
            
            // 计算合价
            if (agg.getTotalQty() != null) {
                if (agg.getTaxExclCompilePrice() != null) {
                    vo.setTaxExclTotalPrice(agg.getTotalQty().multiply(agg.getTaxExclCompilePrice())
                            .setScale(2, RoundingMode.HALF_UP));
                }
                if (agg.getTaxInclCompilePrice() != null) {
                    vo.setTaxInclTotalPrice(agg.getTotalQty().multiply(agg.getTaxInclCompilePrice())
                            .setScale(2, RoundingMode.HALF_UP));
                }
            }
            
            // 用户标记
            WbResourceSummaryDO summary = summaryMap.get(agg.getResourceKey());
            if (summary != null) {
                vo.setId(summary.getId());
                vo.setIsPrint(summary.getIsPrint() != null && summary.getIsPrint() == 1);
                vo.setIsBidMaterial(summary.getIsBidMaterial() != null && summary.getIsBidMaterial() == 1);
                vo.setPriceSource(summary.getPriceSource());
                vo.setRemark(summary.getRemark());
            } else {
                vo.setIsPrint(false);
                vo.setIsBidMaterial(false);
            }
            
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSummary(WbResourceSummaryUpdateReqVO updateReqVO) {
        Long projectId = updateReqVO.getProjectId();
        String resourceKey = updateReqVO.getResourceKey();
        
        // 1. 查询或创建汇总记录
        WbResourceSummaryDO summary = wbResourceSummaryMapper.selectByProjectIdAndResourceKey(projectId, resourceKey);
        if (summary == null) {
            summary = new WbResourceSummaryDO();
            summary.setTenantId(TenantContextHolder.getTenantId());
            summary.setProjectId(projectId);
            summary.setResourceKey(resourceKey);
            summary.setIsPrint(0);
            summary.setIsBidMaterial(0);
        }
        
        // 2. 更新字段
        if (updateReqVO.getIsPrint() != null) {
            summary.setIsPrint(updateReqVO.getIsPrint() ? 1 : 0);
        }
        if (updateReqVO.getIsBidMaterial() != null) {
            summary.setIsBidMaterial(updateReqVO.getIsBidMaterial() ? 1 : 0);
        }
        if (updateReqVO.getPriceSource() != null) {
            summary.setPriceSource(updateReqVO.getPriceSource());
        }
        if (updateReqVO.getRemark() != null) {
            summary.setRemark(updateReqVO.getRemark());
        }
        
        // 3. 保存
        if (summary.getId() == null) {
            wbResourceSummaryMapper.insert(summary);
        } else {
            wbResourceSummaryMapper.updateById(summary);
        }
        
        // 4. 如果修改了编码，同步到工作台工料机
        if (StrUtil.isNotBlank(updateReqVO.getNewCode())) {
            updateResourceCode(projectId, resourceKey, updateReqVO.getNewCode());
        }
    }

    @Override
    public List<WbResourceSourceUnitRespVO> getSourceUnits(Long projectId, String resourceKey) {
        // 1. 获取项目下所有单位工程
        List<WbCompileTreeDO> unitNodes = wbCompileTreeMapper.selectUnitNodesByProjectId(projectId);
        if (CollUtil.isEmpty(unitNodes)) {
            return new ArrayList<>();
        }
        
        // 2. 解析resourceKey获取code/name/spec/unit
        ResourceKeyInfo keyInfo = parseResourceKey(projectId, resourceKey);
        if (keyInfo == null) {
            return new ArrayList<>();
        }
        
        // 3. 统计每个单位工程下该工料机的数量
        List<WbResourceSourceUnitRespVO> result = new ArrayList<>();
        for (WbCompileTreeDO unit : unitNodes) {
            int count = countResourceInUnit(unit.getId(), keyInfo);
            if (count > 0) {
                WbResourceSourceUnitRespVO vo = new WbResourceSourceUnitRespVO();
                vo.setCompileTreeId(unit.getId());
                vo.setUnitName(unit.getName());
                vo.setResourceCount(count);
                result.add(vo);
            }
        }
        
        return result;
    }

    @Override
    public List<WbResourceSourceBoqRespVO> getSourceBoqs(Long compileTreeId, String resourceKey) {
        // 1. 解析resourceKey
        ResourceKeyInfo keyInfo = parseResourceKeyFromDb(compileTreeId, resourceKey);
        if (keyInfo == null) {
            return new ArrayList<>();
        }
        
        // 2. 查询该单位工程下所有定额节点
        List<WbBoqDivisionDO> quotaNodes = wbBoqDivisionMapper.selectQuotaNodesByCompileTreeId(compileTreeId);
        if (CollUtil.isEmpty(quotaNodes)) {
            return new ArrayList<>();
        }
        
        // 3. 查询包含该工料机的定额节点，并获取其父清单节点信息
        List<WbResourceSourceBoqRespVO> result = new ArrayList<>();
        for (WbBoqDivisionDO quotaNode : quotaNodes) {
            // 检查该定额节点是否包含该工料机
            List<WbBoqResourceDO> resources = wbBoqResourceMapper.selectListByDivisionId(quotaNode.getId());
            boolean hasResource = resources.stream().anyMatch(r -> 
                    matchResourceKey(r, keyInfo));
            
            if (hasResource) {
                // 获取父清单节点
                WbBoqDivisionDO boqNode = findParentBoqNode(quotaNode);
                if (boqNode != null) {
                    WbResourceSourceBoqRespVO vo = new WbResourceSourceBoqRespVO();
                    vo.setBoqId(boqNode.getId());
                    vo.setBoqCode(boqNode.getCode());
                    vo.setBoqName(boqNode.getName());
                    vo.setUnit(boqNode.getUnit());
                    vo.setQty(boqNode.getQty());
                    // 从 attributes.tabTypes 获取标签页类型，无 tabTypes 或为空则默认 division
                    vo.setTabType(resolveTabType(boqNode));
                    result.add(vo);
                }
            }
        }
        
        return result;
    }

    // ========== 私有方法 ==========

    /**
     * 获取项目下工料机汇总数据
     */
    private List<ResourceAggregation> getResourceAggregations(Long projectId, String resourceType) {
        return getResourceAggregations(projectId, resourceType, null);
    }

    /**
     * 获取项目下工料机汇总数据（支持单位工程级过滤）
     *
     * @param projectId 项目ID
     * @param resourceType 资源类型过滤（可选）
     * @param compileTreeId 编制模式树的单位工程节点ID（可选，传了只汇总该单位工程）
     */
    private List<ResourceAggregation> getResourceAggregations(Long projectId, String resourceType, Long compileTreeId) {
        // 1. 获取单位工程列表
        List<WbCompileTreeDO> unitNodes;
        if (compileTreeId != null) {
            // 单位工程级：只查指定的单位工程
            WbCompileTreeDO unitNode = wbCompileTreeMapper.selectById(compileTreeId);
            unitNodes = unitNode != null ? Collections.singletonList(unitNode) : new ArrayList<>();
        } else {
            // 项目级：查所有单位工程
            unitNodes = wbCompileTreeMapper.selectUnitNodesByProjectId(projectId);
        }
        if (CollUtil.isEmpty(unitNodes)) {
            return new ArrayList<>();
        }
        
        // 2. 收集所有工料机数据
        Map<String, ResourceAggregation> aggregationMap = new HashMap<>();
        for (WbCompileTreeDO unit : unitNodes) {
            // 获取该单位工程下所有定额节点
            List<WbBoqDivisionDO> quotaNodes = wbBoqDivisionMapper.selectQuotaNodesByCompileTreeId(unit.getId());
            for (WbBoqDivisionDO quotaNode : quotaNodes) {
                // 获取定额节点下的工料机
                List<WbBoqResourceDO> resources = wbBoqResourceMapper.selectListByDivisionId(quotaNode.getId());
                for (WbBoqResourceDO resource : resources) {
                    // 归一化类别（兼容旧数据英文格式）
                    String normalizedType = normalizeResourceType(resource.getResourceType());
                    // 过滤类型
                    if (resourceType != null && !resourceType.equals(normalizedType)) {
                        continue;
                    }
                    // 跳过子工料机（复合工料机的子项）
                    if (resource.getParentId() != null) {
                        continue;
                    }
                    
                    // 生成唯一键
                    String key = generateResourceKey(resource.getCode(), resource.getName(), 
                            resource.getSpec(), resource.getUnit());
                    
                    // 汇总
                    ResourceAggregation agg = aggregationMap.get(key);
                    if (agg == null) {
                        agg = new ResourceAggregation();
                        agg.setResourceKey(key);
                        agg.setCode(resource.getCode());
                        agg.setName(resource.getName());
                        agg.setSpec(resource.getSpec());
                        agg.setUnit(resource.getUnit());
                        agg.setResourceType(normalizedType);
                        agg.setTaxRate(resource.getTaxRate());
                        agg.setTaxExclBasePrice(resource.getTaxExclBasePrice());
                        agg.setTaxInclBasePrice(resource.getTaxInclBasePrice());
                        agg.setTaxExclCompilePrice(resource.getTaxExclCompilePrice());
                        agg.setTaxInclCompilePrice(resource.getTaxInclCompilePrice());
                        agg.setTotalQty(BigDecimal.ZERO);
                        aggregationMap.put(key, agg);
                    }
                    
                    // 累加数量（优先使用调整消耗量，其次使用定额消耗量）
                    BigDecimal qty = resource.getAdjustConsumeQty() != null 
                            ? resource.getAdjustConsumeQty() : resource.getConsumeQty();
                    if (qty != null) {
                        agg.setTotalQty(agg.getTotalQty().add(qty));
                    }
                }
            }
        }
        
        return new ArrayList<>(aggregationMap.values());
    }

    /**
     * 获取评标指定材料汇总数据
     */
    private List<ResourceAggregation> getBidMaterialAggregations(Long projectId) {
        // 1. 获取所有评标指定材料的resourceKey
        List<WbResourceSummaryDO> bidMaterials = wbResourceSummaryMapper.selectBidMaterialsByProjectId(projectId);
        if (CollUtil.isEmpty(bidMaterials)) {
            return new ArrayList<>();
        }
        
        // 2. 获取所有汇总数据
        List<ResourceAggregation> allAggregations = getResourceAggregations(projectId, null);
        
        // 3. 过滤出评标指定材料
        java.util.Set<String> bidKeys = bidMaterials.stream()
                .map(WbResourceSummaryDO::getResourceKey)
                .collect(Collectors.toSet());
        
        return allAggregations.stream()
                .filter(agg -> bidKeys.contains(agg.getResourceKey()))
                .collect(Collectors.toList());
    }

    /**
     * 归一化工料机类别（兼容旧数据英文格式转为中文类别code）
     */
    private String normalizeResourceType(String type) {
        if (type == null) {
            return null;
        }
        switch (type) {
            case "labor":
                return "人";
            case "material":
                return "材";
            case "machine":
                return "机";
            default:
                return type;
        }
    }

    /**
     * 生成资源唯一键
     */
    private String generateResourceKey(String code, String name, String spec, String unit) {
        String raw = StrUtil.nullToEmpty(code) + "|" + 
                     StrUtil.nullToEmpty(name) + "|" + 
                     StrUtil.nullToEmpty(spec) + "|" + 
                     StrUtil.nullToEmpty(unit);
        return DigestUtil.md5Hex(raw);
    }

    /**
     * 更新工料机编码（同步到工作台工料机）
     */
    private void updateResourceCode(Long projectId, String resourceKey, String newCode) {
        // 1. 获取项目下所有单位工程
        List<WbCompileTreeDO> unitNodes = wbCompileTreeMapper.selectUnitNodesByProjectId(projectId);
        if (CollUtil.isEmpty(unitNodes)) {
            return;
        }
        
        // 2. 解析原resourceKey获取原始信息
        ResourceKeyInfo keyInfo = parseResourceKey(projectId, resourceKey);
        if (keyInfo == null) {
            return;
        }
        
        // 3. 遍历所有单位工程，更新匹配的工料机编码
        int updateCount = 0;
        for (WbCompileTreeDO unit : unitNodes) {
            List<WbBoqDivisionDO> quotaNodes = wbBoqDivisionMapper.selectQuotaNodesByCompileTreeId(unit.getId());
            for (WbBoqDivisionDO quotaNode : quotaNodes) {
                List<WbBoqResourceDO> resources = wbBoqResourceMapper.selectListByDivisionId(quotaNode.getId());
                for (WbBoqResourceDO resource : resources) {
                    if (matchResourceKey(resource, keyInfo)) {
                        resource.setCode(newCode);
                        wbBoqResourceMapper.updateById(resource);
                        updateCount++;
                    }
                }
            }
        }
        
        // 4. 更新汇总表的resourceKey
        if (updateCount > 0) {
            String newResourceKey = generateResourceKey(newCode, keyInfo.getName(), 
                    keyInfo.getSpec(), keyInfo.getUnit());
            WbResourceSummaryDO summary = wbResourceSummaryMapper.selectByProjectIdAndResourceKey(projectId, resourceKey);
            if (summary != null) {
                summary.setResourceKey(newResourceKey);
                wbResourceSummaryMapper.updateById(summary);
            }
        }
        
        log.info("[updateResourceCode] 更新工料机编码, projectId={}, oldKey={}, newCode={}, updateCount={}", 
                projectId, resourceKey, newCode, updateCount);
    }

    /**
     * 解析resourceKey获取原始信息
     */
    private ResourceKeyInfo parseResourceKey(Long projectId, String resourceKey) {
        // 通过遍历工料机找到匹配的记录
        List<WbCompileTreeDO> unitNodes = wbCompileTreeMapper.selectUnitNodesByProjectId(projectId);
        for (WbCompileTreeDO unit : unitNodes) {
            ResourceKeyInfo info = parseResourceKeyFromDb(unit.getId(), resourceKey);
            if (info != null) {
                return info;
            }
        }
        return null;
    }

    /**
     * 从数据库解析resourceKey
     */
    private ResourceKeyInfo parseResourceKeyFromDb(Long compileTreeId, String resourceKey) {
        List<WbBoqDivisionDO> quotaNodes = wbBoqDivisionMapper.selectQuotaNodesByCompileTreeId(compileTreeId);
        for (WbBoqDivisionDO quotaNode : quotaNodes) {
            List<WbBoqResourceDO> resources = wbBoqResourceMapper.selectListByDivisionId(quotaNode.getId());
            for (WbBoqResourceDO resource : resources) {
                String key = generateResourceKey(resource.getCode(), resource.getName(), 
                        resource.getSpec(), resource.getUnit());
                if (key.equals(resourceKey)) {
                    ResourceKeyInfo info = new ResourceKeyInfo();
                    info.setCode(resource.getCode());
                    info.setName(resource.getName());
                    info.setSpec(resource.getSpec());
                    info.setUnit(resource.getUnit());
                    return info;
                }
            }
        }
        return null;
    }

    /**
     * 统计单位工程下该工料机的数量
     */
    private int countResourceInUnit(Long compileTreeId, ResourceKeyInfo keyInfo) {
        int count = 0;
        List<WbBoqDivisionDO> quotaNodes = wbBoqDivisionMapper.selectQuotaNodesByCompileTreeId(compileTreeId);
        for (WbBoqDivisionDO quotaNode : quotaNodes) {
            List<WbBoqResourceDO> resources = wbBoqResourceMapper.selectListByDivisionId(quotaNode.getId());
            for (WbBoqResourceDO resource : resources) {
                if (matchResourceKey(resource, keyInfo)) {
                    count++;
                }
            }
        }
        return count;
    }

    /**
     * 匹配工料机是否符合resourceKey
     */
    private boolean matchResourceKey(WbBoqResourceDO resource, ResourceKeyInfo keyInfo) {
        return StrUtil.equals(resource.getCode(), keyInfo.getCode()) &&
               StrUtil.equals(resource.getName(), keyInfo.getName()) &&
               StrUtil.equals(resource.getSpec(), keyInfo.getSpec()) &&
               StrUtil.equals(resource.getUnit(), keyInfo.getUnit());
    }

    /**
     * 查找父清单节点
     */
    private WbBoqDivisionDO findParentBoqNode(WbBoqDivisionDO quotaNode) {
        if (quotaNode.getParentId() == null) {
            return null;
        }
        WbBoqDivisionDO parent = wbBoqDivisionMapper.selectById(quotaNode.getParentId());
        if (parent == null) {
            return null;
        }
        if (WbBoqDivisionDO.NODE_TYPE_BOQ.equals(parent.getNodeType())) {
            return parent;
        }
        // 递归查找
        return findParentBoqNode(parent);
    }

    /**
     * 从节点的 attributes.tabTypes 解析标签页类型
     * 无 tabTypes 或为空数组则默认返回 "division"
     */
    @SuppressWarnings("unchecked")
    private String resolveTabType(WbBoqDivisionDO node) {
        java.util.Map<String, Object> attrs = node.getAttributes();
        if (attrs != null) {
            Object tabTypesObj = attrs.get("tabTypes");
            if (tabTypesObj instanceof java.util.List) {
                java.util.List<?> tabTypes = (java.util.List<?>) tabTypesObj;
                if (!tabTypes.isEmpty()) {
                    return String.valueOf(tabTypes.get(0));
                }
            }
        }
        return "division";
    }

    // ========== 内部类 ==========

    /**
     * 资源汇总数据
     */
    @lombok.Data
    private static class ResourceAggregation {
        private String resourceKey;
        private String code;
        private String name;
        private String spec;
        private String unit;
        private String resourceType;
        private BigDecimal taxRate;
        private BigDecimal totalQty;
        private BigDecimal taxExclBasePrice;
        private BigDecimal taxInclBasePrice;
        private BigDecimal taxExclCompilePrice;
        private BigDecimal taxInclCompilePrice;
    }

    /**
     * 资源唯一键信息
     */
    @lombok.Data
    private static class ResourceKeyInfo {
        private String code;
        private String name;
        private String spec;
        private String unit;
    }
}
