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_RESOURCE_FIELD_CODE_DUPLICATE;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_RESOURCE_FIELD_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_RESOURCE_FIELD_NOT_FIELDS_MAJORS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_UNIT_RESOURCE_FIELD_NOT_SAME_CATALOG;

import com.yhy.module.core.controller.admin.config.vo.ConfigUnitResourceFieldRespVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigUnitResourceFieldSaveReqVO;
import com.yhy.module.core.dal.dataobject.config.ConfigUnitResourceFieldDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO;
import com.yhy.module.core.dal.mysql.config.ConfigUnitResourceFieldMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.service.config.ConfigUnitResourceFieldService;
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 ConfigUnitResourceFieldServiceImpl implements ConfigUnitResourceFieldService {

    @Resource
    private ConfigUnitResourceFieldMapper mapper;
    @Resource
    private QuotaCatalogItemMapper quotaCatalogItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(ConfigUnitResourceFieldSaveReqVO reqVO) {
        validateFieldsMajorsNode(reqVO.getCatalogItemId());
        validateFieldCodeUnique(reqVO.getCatalogItemId(), reqVO.getFieldCode(), null);

        ConfigUnitResourceFieldDO field = ConfigUnitResourceFieldDO.builder()
                .catalogItemId(reqVO.getCatalogItemId())
                .seqNo(reqVO.getSeqNo())
                .fieldName(reqVO.getFieldName())
                .fieldCode(reqVO.getFieldCode())
                .visible(reqVO.getVisible() != null ? reqVO.getVisible() : true)
                .remark(reqVO.getRemark())
                .build();
        field.setSortOrder(calculateSortOrder(reqVO));
        mapper.insert(field);
        return field.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCreate(List<ConfigUnitResourceFieldSaveReqVO> createReqVOs) {
        // 1. 校验并构建 DO 列表
        List<ConfigUnitResourceFieldDO> fields = new ArrayList<>();
        for (ConfigUnitResourceFieldSaveReqVO reqVO : createReqVOs) {
//            validateFieldsMajorsNode(reqVO.getCatalogItemId());
//            validateFieldCodeUnique(reqVO.getCatalogItemId(), reqVO.getFieldCode(), null);
            ConfigUnitResourceFieldDO field = ConfigUnitResourceFieldDO.builder()
                    .catalogItemId(reqVO.getCatalogItemId())
                    .seqNo(reqVO.getSeqNo())
                    .fieldName(reqVO.getFieldName())
                    .fieldCode(reqVO.getFieldCode())
                    .visible(reqVO.getVisible() != null ? reqVO.getVisible() : true)
                    .remark(reqVO.getRemark())
                    .build();
            field.setSortOrder(calculateSortOrder(reqVO));
            fields.add(field);
        }
        // 2. 批量插入
        mapper.insertBatch(fields);
    }

    @Override
    public void update(ConfigUnitResourceFieldSaveReqVO reqVO) {
        ConfigUnitResourceFieldDO exist = mapper.selectById(reqVO.getId());
        if (exist == null) throw exception(CONFIG_UNIT_RESOURCE_FIELD_NOT_EXISTS);
        validateFieldCodeUnique(exist.getCatalogItemId(), reqVO.getFieldCode(), reqVO.getId());

        ConfigUnitResourceFieldDO updateObj = ConfigUnitResourceFieldDO.builder()
                .id(reqVO.getId())
                .seqNo(reqVO.getSeqNo())
                .fieldName(reqVO.getFieldName())
                .fieldCode(reqVO.getFieldCode())
                .visible(reqVO.getVisible())
                .remark(reqVO.getRemark())
                .build();
        mapper.updateById(updateObj);
    }

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

    @Override
    public List<ConfigUnitResourceFieldRespVO> getList(Long catalogItemId) {
        return mapper.selectListByCatalogItemId(catalogItemId).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) {
        ConfigUnitResourceFieldDO n1 = mapper.selectById(nodeId1);
        ConfigUnitResourceFieldDO n2 = mapper.selectById(nodeId2);
        if (n1 == null || n2 == null) throw exception(CONFIG_UNIT_RESOURCE_FIELD_NOT_EXISTS);
        if (!n1.getCatalogItemId().equals(n2.getCatalogItemId())) throw exception(CONFIG_UNIT_RESOURCE_FIELD_NOT_SAME_CATALOG);
        Integer temp = n1.getSortOrder();
        n1.setSortOrder(n2.getSortOrder());
        n2.setSortOrder(temp);
        mapper.updateById(n1);
        mapper.updateById(n2);
    }

    @Override
    public List<String> getHiddenFields(Long catalogItemId) {
        List<String> hidden = new ArrayList<>();
        for (ConfigUnitResourceFieldDO f : mapper.selectListByCatalogItemId(catalogItemId)) {
            // 返回用户勾选的字段（visible=true 表示用户选中了该字段需要隐藏）
            if (Boolean.TRUE.equals(f.getVisible())) hidden.add(f.getFieldCode());
        }
        return hidden;
    }

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

    private void validateFieldCodeUnique(Long catalogItemId, String fieldCode, Long excludeId) {
        for (ConfigUnitResourceFieldDO f : mapper.selectListByCatalogItemId(catalogItemId)) {
            if (f.getFieldCode().equals(fieldCode) && !f.getId().equals(excludeId)) {
                throw exception(CONFIG_UNIT_RESOURCE_FIELD_CODE_DUPLICATE, fieldCode);
            }
        }
    }

    private Integer calculateSortOrder(ConfigUnitResourceFieldSaveReqVO reqVO) {
        String pos = reqVO.getInsertPosition();
        Long refId = reqVO.getReferenceNodeId();
        if (pos == null || "end".equals(pos) || refId == null) {
            return mapper.selectMaxSortOrder(reqVO.getCatalogItemId()) + 1;
        }
        ConfigUnitResourceFieldDO ref = mapper.selectById(refId);
        if (ref == null) return mapper.selectMaxSortOrder(reqVO.getCatalogItemId()) + 1;

        Integer target = "above".equals(pos) ? ref.getSortOrder() : ref.getSortOrder() + 1;
        for (ConfigUnitResourceFieldDO n : mapper.selectListByCatalogItemIdAndSortOrderGe(reqVO.getCatalogItemId(), target)) {
            n.setSortOrder(n.getSortOrder() + 1);
            mapper.updateById(n);
        }
        return target;
    }

    private ConfigUnitResourceFieldRespVO convertToRespVO(ConfigUnitResourceFieldDO f) {
        ConfigUnitResourceFieldRespVO vo = new ConfigUnitResourceFieldRespVO();
        vo.setId(f.getId());
        vo.setCatalogItemId(f.getCatalogItemId());
        vo.setSeqNo(f.getSeqNo());
        vo.setFieldName(f.getFieldName());
        vo.setFieldCode(f.getFieldCode());
        vo.setVisible(f.getVisible());
        vo.setRemark(f.getRemark());
        vo.setSortOrder(f.getSortOrder());
        vo.setCreateTime(f.getCreateTime());
        return vo;
    }
}
