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_FIELD_CODE_DUPLICATE;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_FIELD_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_FIELD_NOT_FIELDS_MAJORS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_FIELD_NOT_SAME_CATALOG;

import com.yhy.module.core.controller.admin.config.vo.ConfigUnitFieldHiddenFieldsRespVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigUnitFieldRespVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigUnitFieldSaveReqVO;
import com.yhy.module.core.dal.dataobject.config.ConfigUnitFieldDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO;
import com.yhy.module.core.dal.mysql.config.ConfigUnitFieldMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.service.config.ConfigUnitFieldService;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
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 ConfigUnitFieldServiceImpl implements ConfigUnitFieldService {

    @Resource
    private ConfigUnitFieldMapper configUnitFieldMapper;
    @Resource
    private QuotaCatalogItemMapper quotaCatalogItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(ConfigUnitFieldSaveReqVO createReqVO) {
        // 1. 校验 catalogItemId 是 fields_majors 类型
        validateFieldsMajorsNode(createReqVO.getCatalogItemId());
        // 2. 校验字段编码唯一
        validateFieldCodeUnique(createReqVO.getCatalogItemId(), createReqVO.getFieldCode(), null);

        // 3. 构建 DO
        ConfigUnitFieldDO field = ConfigUnitFieldDO.builder()
                .catalogItemId(createReqVO.getCatalogItemId())
                .seqNo(createReqVO.getSeqNo())
                .fieldName(createReqVO.getFieldName())
                .fieldCode(createReqVO.getFieldCode())
                .divisionHidden(createReqVO.getDivisionHidden() != null ? createReqVO.getDivisionHidden() : false)
                .measureHidden(createReqVO.getMeasureHidden() != null ? createReqVO.getMeasureHidden() : false)
                .otherHidden(createReqVO.getOtherHidden() != null ? createReqVO.getOtherHidden() : false)
                .summaryHidden(createReqVO.getSummaryHidden() != null ? createReqVO.getSummaryHidden() : false)
                .remark(createReqVO.getRemark())
                .build();

        // 4. 计算排序号
        field.setSortOrder(calculateSortOrder(createReqVO));

        configUnitFieldMapper.insert(field);
        return field.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCreate(List<ConfigUnitFieldSaveReqVO> createReqVOs) {
        // 1. 校验并构建 DO 列表
        List<ConfigUnitFieldDO> fields = new ArrayList<>();
        for (ConfigUnitFieldSaveReqVO reqVO : createReqVOs) {
//            validateFieldsMajorsNode(reqVO.getCatalogItemId());
//            validateFieldCodeUnique(reqVO.getCatalogItemId(), reqVO.getFieldCode(), null);
            ConfigUnitFieldDO field = ConfigUnitFieldDO.builder()
                    .catalogItemId(reqVO.getCatalogItemId())
                    .seqNo(reqVO.getSeqNo())
                    .fieldName(reqVO.getFieldName())
                    .fieldCode(reqVO.getFieldCode())
                    .divisionHidden(reqVO.getDivisionHidden() != null ? reqVO.getDivisionHidden() : false)
                    .measureHidden(reqVO.getMeasureHidden() != null ? reqVO.getMeasureHidden() : false)
                    .otherHidden(reqVO.getOtherHidden() != null ? reqVO.getOtherHidden() : false)
                    .summaryHidden(reqVO.getSummaryHidden() != null ? reqVO.getSummaryHidden() : false)
                    .remark(reqVO.getRemark())
                    .build();
            field.setSortOrder(calculateSortOrder(reqVO));
            fields.add(field);
        }
        // 2. 批量插入
        configUnitFieldMapper.insertBatch(fields);
    }

    @Override
    public void update(ConfigUnitFieldSaveReqVO updateReqVO) {
        // 1. 校验存在
        ConfigUnitFieldDO exist = configUnitFieldMapper.selectById(updateReqVO.getId());
        if (exist == null) {
            throw exception(CONFIG_UNIT_FIELD_NOT_EXISTS);
        }
        // 2. 校验字段编码唯一
        validateFieldCodeUnique(exist.getCatalogItemId(), updateReqVO.getFieldCode(), updateReqVO.getId());

        // 3. 更新
        ConfigUnitFieldDO updateObj = ConfigUnitFieldDO.builder()
                .id(updateReqVO.getId())
                .seqNo(updateReqVO.getSeqNo())
                .fieldName(updateReqVO.getFieldName())
                .fieldCode(updateReqVO.getFieldCode())
                .divisionHidden(updateReqVO.getDivisionHidden())
                .measureHidden(updateReqVO.getMeasureHidden())
                .otherHidden(updateReqVO.getOtherHidden())
                .summaryHidden(updateReqVO.getSummaryHidden())
                .remark(updateReqVO.getRemark())
                .build();
        configUnitFieldMapper.updateById(updateObj);
    }

    @Override
    public void delete(Long id) {
        ConfigUnitFieldDO exist = configUnitFieldMapper.selectById(id);
        if (exist == null) {
            throw exception(CONFIG_UNIT_FIELD_NOT_EXISTS);
        }
        configUnitFieldMapper.deleteById(id);
    }

    @Override
    public List<ConfigUnitFieldRespVO> getList(Long catalogItemId) {
        List<ConfigUnitFieldDO> list = configUnitFieldMapper.selectListByCatalogItemId(catalogItemId);
        return list.stream().sorted(Comparator.comparingInt(a -> a.getSeqNo() != null ? a.getSeqNo() : 0))
                .map(this::convertToRespVO).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(Long nodeId1, Long nodeId2) {
        ConfigUnitFieldDO node1 = configUnitFieldMapper.selectById(nodeId1);
        ConfigUnitFieldDO node2 = configUnitFieldMapper.selectById(nodeId2);
        if (node1 == null || node2 == null) {
            throw exception(CONFIG_UNIT_FIELD_NOT_EXISTS);
        }
        if (!node1.getCatalogItemId().equals(node2.getCatalogItemId())) {
            throw exception(CONFIG_UNIT_FIELD_NOT_SAME_CATALOG);
        }
        Integer temp = node1.getSortOrder();
        node1.setSortOrder(node2.getSortOrder());
        node2.setSortOrder(temp);
        configUnitFieldMapper.updateById(node1);
        configUnitFieldMapper.updateById(node2);
    }

    @Override
    public ConfigUnitFieldHiddenFieldsRespVO getHiddenFields(Long catalogItemId) {
        List<ConfigUnitFieldDO> list = configUnitFieldMapper.selectListByCatalogItemId(catalogItemId);
        List<String> divisionHidden = new ArrayList<>();
        List<String> measureHidden = new ArrayList<>();
        List<String> otherHidden = new ArrayList<>();
        List<String> summaryHidden = new ArrayList<>();
        for (ConfigUnitFieldDO field : list) {
            if (Boolean.TRUE.equals(field.getDivisionHidden())) divisionHidden.add(field.getFieldCode());
            if (Boolean.TRUE.equals(field.getMeasureHidden())) measureHidden.add(field.getFieldCode());
            if (Boolean.TRUE.equals(field.getOtherHidden())) otherHidden.add(field.getFieldCode());
            if (Boolean.TRUE.equals(field.getSummaryHidden())) summaryHidden.add(field.getFieldCode());
        }
        return ConfigUnitFieldHiddenFieldsRespVO.builder()
                .divisionHiddenFields(divisionHidden)
                .measureHiddenFields(measureHidden)
                .otherHiddenFields(otherHidden)
                .summaryHiddenFields(summaryHidden)
                .build();
    }

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

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

    private void validateFieldCodeUnique(Long catalogItemId, String fieldCode, Long excludeId) {
        List<ConfigUnitFieldDO> list = configUnitFieldMapper.selectListByCatalogItemId(catalogItemId);
        for (ConfigUnitFieldDO field : list) {
            if (field.getFieldCode().equals(fieldCode) && !field.getId().equals(excludeId)) {
                throw exception(CONFIG_UNIT_FIELD_CODE_DUPLICATE, fieldCode);
            }
        }
    }

    private Integer calculateSortOrder(ConfigUnitFieldSaveReqVO reqVO) {
        String insertPosition = reqVO.getInsertPosition();
        Long referenceNodeId = reqVO.getReferenceNodeId();

        if (insertPosition == null || ConfigUnitFieldSaveReqVO.INSERT_POSITION_END.equals(insertPosition)
                || referenceNodeId == null) {
            return configUnitFieldMapper.selectMaxSortOrder(reqVO.getCatalogItemId()) + 1;
        }

        ConfigUnitFieldDO refNode = configUnitFieldMapper.selectById(referenceNodeId);
        if (refNode == null) {
            return configUnitFieldMapper.selectMaxSortOrder(reqVO.getCatalogItemId()) + 1;
        }

        Integer targetSortOrder;
        if (ConfigUnitFieldSaveReqVO.INSERT_POSITION_ABOVE.equals(insertPosition)) {
            targetSortOrder = refNode.getSortOrder();
        } else {
            targetSortOrder = refNode.getSortOrder() + 1;
        }

        // 后移
        List<ConfigUnitFieldDO> toShift = configUnitFieldMapper
                .selectListByCatalogItemIdAndSortOrderGe(reqVO.getCatalogItemId(), targetSortOrder);
        for (ConfigUnitFieldDO node : toShift) {
            node.setSortOrder(node.getSortOrder() + 1);
            configUnitFieldMapper.updateById(node);
        }
        return targetSortOrder;
    }

    private ConfigUnitFieldRespVO convertToRespVO(ConfigUnitFieldDO field) {
        ConfigUnitFieldRespVO vo = new ConfigUnitFieldRespVO();
        vo.setId(field.getId());
        vo.setCatalogItemId(field.getCatalogItemId());
        vo.setSeqNo(field.getSeqNo());
        vo.setFieldName(field.getFieldName());
        vo.setFieldCode(field.getFieldCode());
        vo.setDivisionHidden(field.getDivisionHidden());
        vo.setMeasureHidden(field.getMeasureHidden());
        vo.setOtherHidden(field.getOtherHidden());
        vo.setSummaryHidden(field.getSummaryHidden());
        vo.setRemark(field.getRemark());
        vo.setSortOrder(field.getSortOrder());
        vo.setCreateTime(field.getCreateTime());
        return vo;
    }
}
