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

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_TAB_REF_INVALID_TAB_TYPE;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_TAB_REF_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_TAB_REF_NOT_FIELDS_MAJORS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_TAB_REF_NOT_SAME_CATALOG;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_TAB_REF_TEMPLATE_NOT_EXISTS;

import cn.hutool.core.collection.CollUtil;
import com.yhy.module.core.controller.admin.config.vo.ConfigUnitDivisionTemplateRespVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigUnitTabRefRespVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigUnitTabRefSaveReqVO;
import com.yhy.module.core.dal.dataobject.config.ConfigUnitDivisionTemplateDO;
import com.yhy.module.core.dal.dataobject.config.ConfigUnitTabRefDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO;
import com.yhy.module.core.dal.mysql.config.ConfigUnitDivisionTemplateMapper;
import com.yhy.module.core.dal.mysql.config.ConfigUnitTabRefMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.service.config.ConfigUnitTabRefService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
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
@Validated
@Slf4j
public class ConfigUnitTabRefServiceImpl implements ConfigUnitTabRefService {

    @Resource
    private ConfigUnitTabRefMapper tabRefMapper;
    @Resource
    private ConfigUnitDivisionTemplateMapper templateMapper;
    @Resource
    private QuotaCatalogItemMapper quotaCatalogItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRefs(ConfigUnitTabRefSaveReqVO saveReqVO) {
        // 1. 校验
        validateFieldsMajorsNode(saveReqVO.getCatalogItemId());
        validateTabType(saveReqVO.getTabType());

        // 2. 校验所有模板节点存在
        for (Long nodeId : saveReqVO.getTemplateNodeIds()) {
            ConfigUnitDivisionTemplateDO tpl = templateMapper.selectById(nodeId);
            if (tpl == null) throw exception(CONFIG_UNIT_TAB_REF_TEMPLATE_NOT_EXISTS);
        }

        // 3. 查询现有引用
        List<ConfigUnitTabRefDO> existRefs = tabRefMapper.selectListByCatalogAndTab(
                saveReqVO.getCatalogItemId(), saveReqVO.getTabType());
        Set<Long> existNodeIds = existRefs.stream()
                .map(ConfigUnitTabRefDO::getTemplateNodeId).collect(Collectors.toSet());
        Set<Long> newNodeIds = new HashSet<>(saveReqVO.getTemplateNodeIds());

        // 4. 删除不再引用的
        for (ConfigUnitTabRefDO ref : existRefs) {
            if (!newNodeIds.contains(ref.getTemplateNodeId())) {
                tabRefMapper.deleteById(ref.getId());
            }
        }

        // 5. 新增新引用
        int maxSort = tabRefMapper.selectMaxSortOrder(saveReqVO.getCatalogItemId(), saveReqVO.getTabType());
        for (Long nodeId : saveReqVO.getTemplateNodeIds()) {
            if (!existNodeIds.contains(nodeId)) {
                ConfigUnitTabRefDO ref = ConfigUnitTabRefDO.builder()
                        .catalogItemId(saveReqVO.getCatalogItemId())
                        .tabType(saveReqVO.getTabType())
                        .templateNodeId(nodeId)
                        .sortOrder(++maxSort)
                        .build();
                tabRefMapper.insert(ref);
            }
        }
    }

    @Override
    public List<ConfigUnitTabRefRespVO> getList(Long catalogItemId, String tabType) {
        List<ConfigUnitTabRefDO> refs = tabRefMapper.selectListByCatalogAndTab(catalogItemId, tabType);
        if (CollUtil.isEmpty(refs)) return Collections.emptyList();

        // 查询所有模板数据（用于填充详情和子节点）
        List<ConfigUnitDivisionTemplateDO> allTemplates = templateMapper.selectListByCatalogItemId(catalogItemId);
        Map<Long, ConfigUnitDivisionTemplateDO> templateMap = allTemplates.stream()
                .collect(Collectors.toMap(ConfigUnitDivisionTemplateDO::getId, t -> t));

        List<ConfigUnitTabRefRespVO> result = new ArrayList<>();
        for (ConfigUnitTabRefDO ref : refs) {
            ConfigUnitTabRefRespVO vo = new ConfigUnitTabRefRespVO();
            vo.setId(ref.getId());
            vo.setCatalogItemId(ref.getCatalogItemId());
            vo.setTabType(ref.getTabType());
            vo.setTemplateNodeId(ref.getTemplateNodeId());
            vo.setSortOrder(ref.getSortOrder());
            vo.setCreateTime(ref.getCreateTime());

            // 填充模板节点信息
            ConfigUnitDivisionTemplateDO tpl = templateMap.get(ref.getTemplateNodeId());
            if (tpl != null) {
                vo.setNodeType(tpl.getNodeType());
                vo.setCode(tpl.getCode());
                vo.setName(tpl.getName());
                vo.setUnit(tpl.getUnit());

                // 如果是分部节点，填充子节点
                if (ConfigUnitDivisionTemplateDO.NODE_TYPE_DIVISION.equals(tpl.getNodeType())) {
                    List<ConfigUnitDivisionTemplateRespVO> children = allTemplates.stream()
                            .filter(t -> ref.getTemplateNodeId().equals(t.getParentId()))
                            .sorted(Comparator.comparingInt(t -> t.getSortOrder() != null ? t.getSortOrder() : 0))
                            .map(this::convertTemplateToRespVO)
                            .collect(Collectors.toList());
                    vo.setChildren(children);
                }
            }
            result.add(vo);
        }
        return result;
    }

    @Override
    public void delete(Long id) {
        if (tabRefMapper.selectById(id) == null) throw exception(CONFIG_UNIT_TAB_REF_NOT_EXISTS);
        tabRefMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(Long nodeId1, Long nodeId2) {
        ConfigUnitTabRefDO n1 = tabRefMapper.selectById(nodeId1);
        ConfigUnitTabRefDO n2 = tabRefMapper.selectById(nodeId2);
        if (n1 == null || n2 == null) throw exception(CONFIG_UNIT_TAB_REF_NOT_EXISTS);
        if (!n1.getCatalogItemId().equals(n2.getCatalogItemId())) throw exception(CONFIG_UNIT_TAB_REF_NOT_SAME_CATALOG);

        Integer temp = n1.getSortOrder();
        n1.setSortOrder(n2.getSortOrder());
        n2.setSortOrder(temp);
        tabRefMapper.updateById(n1);
        tabRefMapper.updateById(n2);
    }

    private void validateFieldsMajorsNode(Long catalogItemId) {
        QuotaCatalogItemDO node = quotaCatalogItemMapper.selectById(catalogItemId);
        if (node == null || !"fields_majors".equals(node.getNodeType())) {
            throw exception(CONFIG_UNIT_TAB_REF_NOT_FIELDS_MAJORS);
        }
    }

    private void validateTabType(String tabType) {
        if (!ConfigUnitTabRefDO.VALID_TAB_TYPES.contains(tabType)) {
            throw exception(CONFIG_UNIT_TAB_REF_INVALID_TAB_TYPE);
        }
    }

    private ConfigUnitDivisionTemplateRespVO convertTemplateToRespVO(ConfigUnitDivisionTemplateDO node) {
        ConfigUnitDivisionTemplateRespVO vo = new ConfigUnitDivisionTemplateRespVO();
        vo.setId(node.getId());
        vo.setCatalogItemId(node.getCatalogItemId());
        vo.setParentId(node.getParentId());
        vo.setNodeType(node.getNodeType());
        vo.setCode(node.getCode());
        vo.setName(node.getName());
        vo.setUnit(node.getUnit());
        vo.setSortOrder(node.getSortOrder());
        vo.setCreateTime(node.getCreateTime());
        return vo;
    }
}
