package com.czg.service.product.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.constants.SystemConstants;
import com.czg.enums.CrudEnum;
import com.czg.exception.CzgException;
import com.czg.product.dto.ConsInfoDTO;
import com.czg.product.dto.ProductBriefDTO;
import com.czg.product.entity.ConsGroup;
import com.czg.product.entity.ConsInfo;
import com.czg.product.entity.ProdConsRelation;
import com.czg.product.param.ConsInfoParam;
import com.czg.product.param.ConsSubUnitParam;
import com.czg.product.service.ConsInfoService;
import com.czg.product.vo.ConsStatisticsVo;
import com.czg.product.vo.ConsStockRecord;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsGroupMapper;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ConsStockFlowMapper;
import com.czg.service.product.mapper.ProdConsRelationMapper;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 耗材信息
 *
 * @author Tankaikai tankaikai@aliyun.com
 * @since 1.0 2025-02-20
 */
@DubboService
@AllArgsConstructor
public class ConsInfoServiceImpl extends ServiceImpl<ConsInfoMapper, ConsInfo> implements ConsInfoService {

    private final ProdConsRelationMapper prodConsRelationMapper;
    private final ConsGroupMapper consGroupMapper;
    private final ConsStockFlowMapper consStockFlowMapper;

    private QueryWrapper buildQueryWrapper(ConsInfoDTO param) {
        QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
        if (ObjUtil.isNotNull(param.getConsGroupId())) {
            queryWrapper.eq(ConsInfo::getConsGroupId, param.getConsGroupId());
        }
        if (StrUtil.isNotEmpty(param.getConName())) {
            queryWrapper.like(ConsInfo::getConName, param.getConName());
        }
        if (StrUtil.isNotEmpty(param.getBeginTime())) {
            queryWrapper.ge(ConsInfo::getCreateTime, param.getBeginTime());
        }
        if (StrUtil.isNotEmpty(param.getEndTime())) {
            queryWrapper.le(ConsInfo::getCreateTime, param.getEndTime());
        }
        Long shopId = StpKit.USER.getShopId(0L);
        queryWrapper.eq(ConsInfo::getShopId, shopId);
        queryWrapper.orderBy(ConsInfo::getId, false);
        return queryWrapper;
    }

    @Override
    public Page<ConsInfoDTO> getConsInfoPage(ConsInfoDTO param) {
        QueryWrapper queryWrapper = buildQueryWrapper(param);
        Page<ConsInfoDTO> page = super.pageAs(PageUtil.buildPage(), queryWrapper, ConsInfoDTO.class);
        List<ConsGroup> consGroupList = consGroupMapper.selectListByQuery(QueryWrapper.create().eq(ConsGroup::getShopId, param.getShopId()));
        Map<Long, String> collect = consGroupList.stream().collect(Collectors.toMap(ConsGroup::getId, ConsGroup::getName));
        page.getRecords().parallelStream().forEach(item -> {
            List<ProductBriefDTO> productList = prodConsRelationMapper.getProductListByConId(item.getId());
            item.setProductList(productList);
            String consGroupName = collect.get(item.getConsGroupId());
            item.setConsGroupName(consGroupName);
        });
        return page;
    }

    @Override
    public List<ConsInfoDTO> getConsInfoList(ConsInfoDTO param) {
        QueryWrapper queryWrapper = buildQueryWrapper(param);
        queryWrapper.eq(ConsInfo::getStatus, SystemConstants.OneZero.ONE);
        List<ConsInfoDTO> list = super.listAs(queryWrapper, ConsInfoDTO.class);
        List<ConsGroup> consGroupList = consGroupMapper.selectListByQuery(QueryWrapper.create().eq(ConsGroup::getShopId, param.getShopId()));
        Map<Long, String> collect = consGroupList.stream().collect(Collectors.toMap(ConsGroup::getId, ConsGroup::getName));
        list.parallelStream().forEach(item -> {
            List<ProductBriefDTO> productList = prodConsRelationMapper.getProductListByConId(item.getId());
            item.setProductList(productList);
            String consGroupName = collect.get(item.getConsGroupId());
            item.setConsGroupName(consGroupName);
        });
        return list;
    }

    @Override
    public List<ConsStockRecord> getConsStockList(Long shopId) {
        return listAs(query().eq(ConsInfo::getShopId, shopId).eq(ConsInfo::getIsStock, SystemConstants.OneZero.ONE), ConsStockRecord.class);
    }

    @Override
    public ConsInfoDTO getConsInfoById(Long id) {
        Long shopId = StpKit.USER.getShopId(0L);
        ConsInfoDTO data = super.getOneAs(query().eq(ConsInfo::getId, id).eq(ConsInfo::getShopId, shopId), ConsInfoDTO.class);
        List<ProductBriefDTO> productList = prodConsRelationMapper.getProductListByConId(data.getId());
        data.setProductList(productList);
        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addConsInfo(ConsInfoDTO dto) {
        Long shopId = StpKit.USER.getShopId(0L);
        boolean exists = super.exists(query().eq(ConsInfo::getConName, dto.getConName()).eq(ConsInfo::getShopId, shopId));
        if (exists) {
            throw new CzgException("耗材信息已存在");
        }
        ConsInfo entity = BeanUtil.copyProperties(dto, ConsInfo.class);
        entity.setStockNumber(BigDecimal.ZERO);
        entity.setStatus(SystemConstants.OneZero.ONE);
        //entity.setConWarning(BigDecimal.ZERO);
        if (dto.getIsStock() == null) {
            entity.setIsStock(SystemConstants.OneZero.ZERO);
        }
        entity.setShopId(shopId);
        super.save(entity);
        dto.setId(entity.getId());
        return true;
    }

    @Override
    public boolean updateConsInfo(ConsInfoDTO dto) {
        Long shopId = StpKit.USER.getShopId(0L);
        dto.setShopId(shopId);
        boolean exists = super.exists(query().eq(ConsInfo::getConName, dto.getConName()).eq(ConsInfo::getShopId, shopId).ne(ConsInfo::getId, dto.getId()));
        if (exists) {
            throw new CzgException("耗材信息已存在");
        }
        ConsInfo entity = BeanUtil.copyProperties(dto, ConsInfo.class);
        super.updateById(entity);
        return true;
    }

    @Override
    public boolean deleteConsInfo(Long id) {
        Long shopId = StpKit.USER.getShopId(0L);
        super.remove(query().eq(ConsInfo::getId, id).eq(ConsInfo::getShopId, shopId));
        prodConsRelationMapper.deleteByQuery(query().eq(ProdConsRelation::getConsInfoId, id));
        return true;
    }

    @Override
    public void disableConsInfo(Long id) {
        Long shopId = StpKit.USER.getShopId(0L);
        UpdateChain.of(ConsInfo.class)
                .set(ConsInfo::getStatus, SystemConstants.OneZero.ZERO)
                .eq(ConsInfo::getId, id)
                .eq(ConsInfo::getShopId, shopId)
                .update();
    }

    @Override
    public void enableConsInfo(Long id) {
        Long shopId = StpKit.USER.getShopId(0L);
        UpdateChain.of(ConsInfo.class)
                .set(ConsInfo::getStatus, SystemConstants.OneZero.ONE)
                .eq(ConsInfo::getId, id)
                .eq(ConsInfo::getShopId, shopId)
                .update();
    }

    @Override
    public void onOffConsInfo(Long id, Integer isStock) {
        Long shopId = StpKit.USER.getShopId(0L);
        ConsInfo entity = super.getOne(query().eq(ConsInfo::getId, id).eq(ConsInfo::getShopId, shopId));
        entity.setIsStock(isStock);
        super.updateById(entity);
    }


    @Override
    public void modifySubUnit(ConsSubUnitParam param) {
        Long shopId = StpKit.USER.getShopId(0L);
        if (CrudEnum.ADD.value().equals(param.getModifyFlag())) {
            UpdateChain.of(ConsInfo.class)
                    .set(ConsInfo::getConUnitTwo, param.getConUnitTwo())
                    .set(ConsInfo::getConUnitTwoConvert, param.getConUnitTwoConvert())
                    .set(ConsInfo::getDefaultUnit, param.getDefaultUnit())
                    .eq(ConsInfo::getId, param.getId())
                    .eq(ConsInfo::getShopId, shopId)
                    .update();
        } else if (CrudEnum.DELETE.value().equals(param.getModifyFlag())) {
            UpdateChain.of(ConsInfo.class)
                    .set(ConsInfo::getConUnitTwo, null)
                    .set(ConsInfo::getConUnitTwoConvert, null)
                    .set(ConsInfo::getDefaultUnit, null)
                    .eq(ConsInfo::getId, param.getId())
                    .eq(ConsInfo::getShopId, shopId)
                    .update();
        }
    }

    @Override
    public ConsStatisticsVo statistics(ConsInfoParam param) {
        ConsStatisticsVo data = consStockFlowMapper.getConsStatistics(param);
        if (data == null) {
            data = new ConsStatisticsVo();
        }
        return data;
    }

}
