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

import cn.hutool.core.collection.CollUtil;
import com.yhy.module.core.controller.admin.boq.vo.BoqSubItemRespVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqSubItemSaveReqVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqSubItemSwapSortReqVO;
import com.yhy.module.core.dal.dataobject.boq.BoqSubItemDO;
import com.yhy.module.core.dal.mysql.boq.BoqSubItemMapper;
import com.yhy.module.core.service.boq.BoqSubItemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yhy.module.core.enums.ErrorCodeConstants.*;

/**
 * 清单子项 Service 实现类
 *
 * @author yhy
 */
@Service
@Validated
@Slf4j
public class BoqSubItemServiceImpl implements BoqSubItemService {

    @Resource
    private BoqSubItemMapper boqSubItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createBoqSubItem(BoqSubItemSaveReqVO createReqVO) {
        // 1. 校验编码唯一性
        validateCodeUnique(null, createReqVO.getCode());

        // 2. 构建DO对象
        BoqSubItemDO boqSubItem = buildBoqSubItemDO(createReqVO);

        // 3. 设置排序
        if (boqSubItem.getSortOrder() == null) {
            boqSubItem.setSortOrder(getNextSortOrder(createReqVO.getBoqItemTreeId()));
        }

        // 4. 插入数据库
        boqSubItemMapper.insert(boqSubItem);

        return boqSubItem.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBoqSubItem(BoqSubItemSaveReqVO updateReqVO) {
        // 1. 校验子项存在
        validateBoqSubItemExists(updateReqVO.getId());

        // 2. 校验编码唯一性
        validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());

        // 3. 构建更新对象
        BoqSubItemDO updateObj = BoqSubItemDO.builder()
                .id(updateReqVO.getId())
                .code(updateReqVO.getCode())
                .name(updateReqVO.getName())
                .unit(updateReqVO.getUnit())
                .description(updateReqVO.getDescription())
                .sortOrder(updateReqVO.getSortOrder())
                .attributes(updateReqVO.getAttributes())
                .build();

        // 4. 更新数据库
        boqSubItemMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBoqSubItem(Long id) {
        // 1. 校验子项存在
        validateBoqSubItemExists(id);

        // 2. 删除子项
        boqSubItemMapper.deleteById(id);
    }

    @Override
    public BoqSubItemRespVO getBoqSubItem(Long id) {
        BoqSubItemDO item = boqSubItemMapper.selectById(id);
        if (item == null) {
            return null;
        }
        return convertToRespVO(item);
    }

    @Override
    public List<BoqSubItemRespVO> getBoqSubItemList(Long boqItemTreeId) {
        List<BoqSubItemDO> items = boqSubItemMapper.selectListByBoqItemTreeId(boqItemTreeId);
        return items.stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(BoqSubItemSwapSortReqVO swapReqVO) {
        // 1. 查询两个子项（加锁）
        BoqSubItemDO item1 = boqSubItemMapper.selectById(swapReqVO.getItemId1());
        BoqSubItemDO item2 = boqSubItemMapper.selectById(swapReqVO.getItemId2());

        if (item1 == null || item2 == null) {
            throw exception(BOQ_SUB_ITEM_NOT_EXISTS);
        }

        // 2. 校验是否属于同一清单项树
        if (!item1.getBoqItemTreeId().equals(item2.getBoqItemTreeId())) {
            throw exception(BOQ_SUB_ITEM_NOT_SAME_TREE);
        }

        // 3. 交换排序值
        Integer tempSort = item1.getSortOrder();
        item1.setSortOrder(item2.getSortOrder());
        item2.setSortOrder(tempSort);

        // 4. 更新数据库
        boqSubItemMapper.updateById(item1);
        boqSubItemMapper.updateById(item2);

        log.info("[swapSort] 交换子项[{}]和子项[{}]的排序成功", swapReqVO.getItemId1(), swapReqVO.getItemId2());
    }

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

    /**
     * 校验编码唯一性
     */
    private void validateCodeUnique(Long id, String code) {
        BoqSubItemDO existing = boqSubItemMapper.selectByCode(code);
        if (existing != null && !existing.getId().equals(id)) {
            throw exception(BOQ_SUB_ITEM_CODE_DUPLICATE, code);
        }
    }

    /**
     * 校验子项存在
     */
    private BoqSubItemDO validateBoqSubItemExists(Long id) {
        BoqSubItemDO item = boqSubItemMapper.selectById(id);
        if (item == null) {
            throw exception(BOQ_SUB_ITEM_NOT_EXISTS);
        }
        return item;
    }

    /**
     * 构建DO对象
     */
    private BoqSubItemDO buildBoqSubItemDO(BoqSubItemSaveReqVO reqVO) {
        return BoqSubItemDO.builder()
                .id(reqVO.getId())
                .boqItemTreeId(reqVO.getBoqItemTreeId())
                .code(reqVO.getCode())
                .name(reqVO.getName())
                .unit(reqVO.getUnit())
                .description(reqVO.getDescription())
                .sortOrder(reqVO.getSortOrder())
                .attributes(reqVO.getAttributes())
                .build();
    }

    /**
     * 获取下一个排序值
     */
    private Integer getNextSortOrder(Long boqItemTreeId) {
        List<BoqSubItemDO> items = boqSubItemMapper.selectListByBoqItemTreeId(boqItemTreeId);
        if (CollUtil.isEmpty(items)) {
            return 1;
        }
        return items.stream()
                .mapToInt(BoqSubItemDO::getSortOrder)
                .max()
                .orElse(0) + 1;
    }

    /**
     * 转换为RespVO
     */
    private BoqSubItemRespVO convertToRespVO(BoqSubItemDO item) {
        BoqSubItemRespVO vo = new BoqSubItemRespVO();
        vo.setId(item.getId());
        vo.setBoqItemTreeId(item.getBoqItemTreeId());
        vo.setCode(item.getCode());
        vo.setName(item.getName());
        vo.setUnit(item.getUnit());
        vo.setDescription(item.getDescription());
        vo.setSortOrder(item.getSortOrder());
        vo.setAttributes(item.getAttributes());
        vo.setCreateTime(item.getCreateTime());
        vo.setUpdateTime(item.getUpdateTime());
        return vo;
    }
}
