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_DIV_TPL_BOQ_PARENT_MUST_DIVISION;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_DIV_TPL_INVALID_NODE_TYPE;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_DIV_TPL_INVALID_TAB_TYPE;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_DIV_TPL_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_DIV_TPL_NOT_FIELDS_MAJORS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_DIV_TPL_NOT_SAME_LEVEL;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_DIV_TPL_PARENT_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.ConfigUnitDivisionTemplateSaveReqVO;
import com.yhy.module.core.dal.dataobject.config.ConfigUnitDivisionTemplateDO;
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.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.service.config.ConfigUnitDivisionTemplateService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
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 实现
 * 四个标签页（分部分项/措施项目/其他项目/单位汇总）各自独立维护模板数据
 */
@Service
@Validated
@Slf4j
public class ConfigUnitDivisionTemplateServiceImpl implements ConfigUnitDivisionTemplateService {

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(ConfigUnitDivisionTemplateSaveReqVO reqVO) {
        validateFieldsMajorsNode(reqVO.getCatalogItemId());
        validateNodeType(reqVO.getNodeType());
        validateTabType(reqVO.getTabType());
        validateParentNode(reqVO);

        ConfigUnitDivisionTemplateDO node = ConfigUnitDivisionTemplateDO.builder()
                .catalogItemId(reqVO.getCatalogItemId())
                .parentId(reqVO.getParentId())
                .nodeType(reqVO.getNodeType())
                .tabType(reqVO.getTabType())
                .code(reqVO.getCode())
                .name(reqVO.getName())
                .unit(reqVO.getUnit())
                .attributes(reqVO.getAttributes())
                .rate(reqVO.getRate())
                .remark(reqVO.getRemark())
                .costCode(reqVO.getCostCode())
                .build();

        node.setSortOrder(calculateSortOrder(reqVO));
        node.setPath(buildPath(reqVO.getParentId()));
        templateMapper.insert(node);

        // 更新路径（包含自身ID）
        String[] currentPath = node.getPath() != null ? node.getPath() : new String[]{};
        String[] newPath = Arrays.copyOf(currentPath, currentPath.length + 1);
        newPath[currentPath.length] = String.valueOf(node.getId());
        node.setPath(newPath);
        templateMapper.updateById(node);

        return node.getId();
    }

    @Override
    public void update(ConfigUnitDivisionTemplateSaveReqVO reqVO) {
        ConfigUnitDivisionTemplateDO exist = templateMapper.selectById(reqVO.getId());
        if (exist == null) throw exception(CONFIG_UNIT_DIV_TPL_NOT_EXISTS);

        ConfigUnitDivisionTemplateDO updateObj = new ConfigUnitDivisionTemplateDO();
        updateObj.setId(reqVO.getId());
        updateObj.setCode(reqVO.getCode());
        updateObj.setName(reqVO.getName());
        updateObj.setUnit(reqVO.getUnit());
        updateObj.setAttributes(reqVO.getAttributes());
        updateObj.setRate(reqVO.getRate());
        updateObj.setRemark(reqVO.getRemark());
        updateObj.setCostCode(reqVO.getCostCode());
        // 不允许修改 nodeType、parentId、tabType
        templateMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        ConfigUnitDivisionTemplateDO exist = templateMapper.selectById(id);
        if (exist == null) throw exception(CONFIG_UNIT_DIV_TPL_NOT_EXISTS);

        // 级联删除子节点
        List<ConfigUnitDivisionTemplateDO> children = templateMapper.selectListByParentId(id);
        if (CollUtil.isNotEmpty(children)) {
            for (ConfigUnitDivisionTemplateDO child : children) {
                delete(child.getId());
            }
        }

        templateMapper.deleteById(id);
        log.info("[delete] 删除模板节点 id={}, tabType={}", id, exist.getTabType());
    }

    @Override
    public List<ConfigUnitDivisionTemplateRespVO> getTree(Long catalogItemId, String tabType) {
        validateTabType(tabType);
        List<ConfigUnitDivisionTemplateDO> list = templateMapper.selectListByCatalogItemIdAndTabType(catalogItemId, tabType);
        return buildTree(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(Long nodeId1, Long nodeId2) {
        ConfigUnitDivisionTemplateDO n1 = templateMapper.selectById(nodeId1);
        ConfigUnitDivisionTemplateDO n2 = templateMapper.selectById(nodeId2);
        if (n1 == null || n2 == null) throw exception(CONFIG_UNIT_DIV_TPL_NOT_EXISTS);
        if (!Objects.equals(n1.getParentId(), n2.getParentId())) throw exception(CONFIG_UNIT_DIV_TPL_NOT_SAME_LEVEL);

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

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

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

    private void validateNodeType(String nodeType) {
        if (!ConfigUnitDivisionTemplateDO.NODE_TYPE_DIVISION.equals(nodeType)
                && !ConfigUnitDivisionTemplateDO.NODE_TYPE_BOQ.equals(nodeType)) {
            throw exception(CONFIG_UNIT_DIV_TPL_INVALID_NODE_TYPE);
        }
    }

    /** 校验标签页类型 */
    private void validateTabType(String tabType) {
        if (!ConfigUnitDivisionTemplateDO.VALID_TAB_TYPES.contains(tabType)) {
            throw exception(CONFIG_UNIT_DIV_TPL_INVALID_TAB_TYPE);
        }
    }

    private void validateParentNode(ConfigUnitDivisionTemplateSaveReqVO reqVO) {
        if (reqVO.getParentId() != null) {
            ConfigUnitDivisionTemplateDO parent = templateMapper.selectById(reqVO.getParentId());
            if (parent == null) throw exception(CONFIG_UNIT_DIV_TPL_PARENT_NOT_EXISTS);
            // 清单只能在分部下创建
            if (ConfigUnitDivisionTemplateDO.NODE_TYPE_BOQ.equals(reqVO.getNodeType())
                    && !ConfigUnitDivisionTemplateDO.NODE_TYPE_DIVISION.equals(parent.getNodeType())) {
                throw exception(CONFIG_UNIT_DIV_TPL_BOQ_PARENT_MUST_DIVISION);
            }
            // 父节点必须属于同一标签页
            if (!Objects.equals(parent.getTabType(), reqVO.getTabType())) {
                throw exception(CONFIG_UNIT_DIV_TPL_PARENT_NOT_EXISTS);
            }
        } else {
            // 无父节点时，只能创建分部
            if (ConfigUnitDivisionTemplateDO.NODE_TYPE_BOQ.equals(reqVO.getNodeType())) {
                throw exception(CONFIG_UNIT_DIV_TPL_BOQ_PARENT_MUST_DIVISION);
            }
        }
    }

    private String[] buildPath(Long parentId) {
        if (parentId == null) return new String[]{};
        ConfigUnitDivisionTemplateDO parent = templateMapper.selectById(parentId);
        return parent != null && parent.getPath() != null ? parent.getPath() : new String[]{};
    }

    private Integer calculateSortOrder(ConfigUnitDivisionTemplateSaveReqVO reqVO) {
        String pos = reqVO.getInsertPosition();
        Long refId = reqVO.getReferenceNodeId();
        if (pos == null || ConfigUnitDivisionTemplateSaveReqVO.INSERT_POSITION_END.equals(pos) || refId == null) {
            return templateMapper.selectMaxSortOrderByParentId(reqVO.getCatalogItemId(), reqVO.getParentId(), reqVO.getTabType()) + 1;
        }
        ConfigUnitDivisionTemplateDO ref = templateMapper.selectById(refId);
        if (ref == null) {
            return templateMapper.selectMaxSortOrderByParentId(reqVO.getCatalogItemId(), reqVO.getParentId(), reqVO.getTabType()) + 1;
        }
        Integer target = ConfigUnitDivisionTemplateSaveReqVO.INSERT_POSITION_ABOVE.equals(pos)
                ? ref.getSortOrder() : ref.getSortOrder() + 1;
        for (ConfigUnitDivisionTemplateDO n : templateMapper.selectListByParentIdAndSortOrderGe(ref.getParentId(), target)) {
            n.setSortOrder(n.getSortOrder() + 1);
            templateMapper.updateById(n);
        }
        return target;
    }

    private List<ConfigUnitDivisionTemplateRespVO> buildTree(List<ConfigUnitDivisionTemplateDO> list) {
        Map<Long, ConfigUnitDivisionTemplateRespVO> voMap = new LinkedHashMap<>();
        for (ConfigUnitDivisionTemplateDO node : list) {
            voMap.put(node.getId(), convertToRespVO(node));
        }
        List<ConfigUnitDivisionTemplateRespVO> roots = new ArrayList<>();
        for (ConfigUnitDivisionTemplateRespVO vo : voMap.values()) {
            if (vo.getParentId() == null) {
                roots.add(vo);
            } else {
                ConfigUnitDivisionTemplateRespVO parent = voMap.get(vo.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) parent.setChildren(new ArrayList<>());
                    parent.getChildren().add(vo);
                } else {
                    roots.add(vo);
                }
            }
        }
        return roots;
    }

    private ConfigUnitDivisionTemplateRespVO convertToRespVO(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.setTabType(node.getTabType());
        vo.setAttributes(node.getAttributes());
        vo.setRate(node.getRate());
        vo.setRemark(node.getRemark());
        vo.setCostCode(node.getCostCode());
        vo.setCreateTime(node.getCreateTime());
        return vo;
    }
}
