package com.yc.ship.module.product.service.productBase;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.TreeNode;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.yc.ship.module.product.controller.admin.productBase.vo.ProductBasePageReqVO;
import com.yc.ship.module.product.controller.admin.productBase.vo.ProductBaseRespVO;
import com.yc.ship.module.product.controller.admin.productBase.vo.ProductBaseSaveReqVO;
import com.yc.ship.module.product.controller.admin.productBase.vo.ShipRespVO;
import com.yc.ship.module.product.dal.dataobject.productBase.ProductBaseDO;
import com.yc.ship.module.product.dal.mysql.productBase.ProductBaseMapper;
import com.yc.ship.module.resource.controller.admin.baseprice.vo.ProductBasePriceRespVO;
import com.yc.ship.module.resource.controller.admin.baseprice.vo.ProductBasePriceSaveReqVO;
import com.yc.ship.module.resource.controller.admin.checkchannel.vo.CheckChannelRespVO;
import com.yc.ship.module.resource.controller.admin.checkchannel.vo.CheckChannelSaveReqVO;
import com.yc.ship.module.resource.controller.admin.resource.vo.ResourceSimpleRespVO;
import com.yc.ship.module.resource.dal.dataobject.checkchannel.CheckChannelDO;
import com.yc.ship.module.resource.dal.dataobject.project.ProjectDO;
import com.yc.ship.module.resource.dal.dataobject.resource.ResourceDO;
import com.yc.ship.module.resource.dal.mysql.checkchannel.CheckChannelMapper;
import com.yc.ship.module.resource.dal.mysql.resource.ResourceMapper;
import com.yc.ship.module.resource.enums.ErrorCodeConstants;
import com.yc.ship.module.resource.enums.UseStatusEnum;
import com.yc.ship.module.resource.service.baseprice.ProductBasePriceService;
import com.yc.ship.module.resource.service.checkchannel.CheckChannelService;
import com.yc.ship.module.resource.service.project.ProjectService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;


/**
 * 基础产品 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@RequiredArgsConstructor
public class ProductBaseServiceImpl implements ProductBaseService {

    private final ProductBaseMapper baseMapper;
    private final ResourceMapper resourceMapper;
    private final CheckChannelMapper checkChannelMapper;

    private final CheckChannelService checkChannelService;
    private final ProjectService projectService;
    private final ProductBasePriceService basePriceService;

    @Override
    @Transactional
    public Long createBase(ProductBaseSaveReqVO createReqVO) {
        // 插入
        ProductBaseDO base = BeanUtils.toBean(createReqVO, ProductBaseDO.class);
        base.setId(IdWorker.getId(base));
        base.setDeleted(false);
        baseMapper.insert(base);

        List<CheckChannelSaveReqVO> channelReqVOList = createReqVO.getCheckChannelList();
        if (CollectionUtil.isNotEmpty(channelReqVOList)) {
            for (CheckChannelSaveReqVO channelReqVO : channelReqVOList) {
                CheckChannelDO checkChannelDO = BeanUtils.toBean(channelReqVO, CheckChannelDO.class);
                checkChannelDO.setProductId(base.getId());
                checkChannelMapper.insert(checkChannelDO);
            }
        }
        List<ProductBasePriceSaveReqVO> basePriceReqVOList = createReqVO.getBasePriceList();
        if (CollectionUtil.isNotEmpty(basePriceReqVOList)) {
            for (ProductBasePriceSaveReqVO basePriceSaveReqVO : basePriceReqVOList) {
                basePriceSaveReqVO.setProductBaseId(base.getId());
                basePriceService.createBasePrice(basePriceSaveReqVO);
            }
        }
        // 返回
        return base.getId();
    }

    @Override
    @Transactional
    public void updateBase(ProductBaseSaveReqVO updateReqVO) {
        // 校验存在
        ProductBaseDO baseDO = validateBaseExists(updateReqVO.getId());
        // 更新
        ProductBaseDO updateObj = BeanUtils.toBean(updateReqVO, ProductBaseDO.class);

        baseMapper.updateById(updateObj);

        List<CheckChannelSaveReqVO> channelReqVOList = updateReqVO.getCheckChannelList();
        if (CollectionUtil.isNotEmpty(channelReqVOList)) {
            if (channelReqVOList.get(0).getId() != -1) {
                checkChannelService.deleteByProductId(baseDO.getId());
            }
            for (CheckChannelSaveReqVO channelReqVO : channelReqVOList) {
                channelReqVO.setId(null);
                channelReqVO.setProductId(baseDO.getId());
                checkChannelService.create(channelReqVO);
            }
        } else {
            checkChannelService.deleteByProductId(baseDO.getId());
        }
        List<ProductBasePriceSaveReqVO> basePriceList = updateReqVO.getBasePriceList();
        if (CollectionUtil.isNotEmpty(basePriceList)) {
            // 删除原规格并添加新规格
            basePriceService.deleteByProductBaseId(updateObj.getId());
            for (ProductBasePriceSaveReqVO basePriceSaveReqVO : basePriceList) {
                basePriceSaveReqVO.setProductBaseId(updateObj.getId());
                basePriceService.createBasePrice(basePriceSaveReqVO);
            }
        }
    }

    @Override
    public void deleteBase(Long id) {
        // 校验存在
        validateBaseExists(id);
        basePriceService.deleteByProductBaseId(id);
        baseMapper.deleteById(id);
    }

    private ProductBaseDO validateBaseExists(Long id) {
        ProductBaseDO productBaseDO = baseMapper.selectById(id);
        if (productBaseDO == null) {
            throw exception(ErrorCodeConstants.BASE_NOT_EXISTS);
        }
        return productBaseDO;
    }

    @Override
    public ProductBaseRespVO getBase(Long id) {
        ProductBaseDO base = baseMapper.selectById(id);
        ProductBaseRespVO baseRespVO = BeanUtils.toBean(base, ProductBaseRespVO.class);
        List<CheckChannelRespVO> channelRespVOList = checkChannelService.getCheckChannelByBase(id);
        List<ProductBasePriceRespVO> priceRespVOList = basePriceService.queryPriceByBase(id);
        baseRespVO.setCheckChannelList(channelRespVOList);
        baseRespVO.setBasePriceList(priceRespVOList);
        return baseRespVO;
    }

    @Override
    public PageResult<ProductBaseDO> getBasePage(ProductBasePageReqVO pageReqVO) {
        //联表查询
        MPJLambdaWrapper<ProductBaseDO> wrapper = new MPJLambdaWrapperX<ProductBaseDO>()
                .selectAll(ProductBaseDO.class)
                .selectAs(ProductBaseDO::getStock, ProductBaseDO::getStock)
                .likeIfPresent(ProductBaseDO::getName, pageReqVO.getName())
                .eqIfPresent(ProductBaseDO::getProjectId, pageReqVO.getProjectId())
                .orderByDesc(ProductBaseDO::getId);

        return baseMapper.selectJoinPage(pageReqVO, ProductBaseDO.class, wrapper);
    }

    @Override
    public PageResult<ProductBaseRespVO> queryBasePage(ProductBasePageReqVO pageReqVO) {
        IPage<ProductBaseRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        IPage<ProductBaseRespVO> iPage = baseMapper.queryProductBasePage(page, pageReqVO);
        iPage.getRecords().forEach(vo -> {
            List<CheckChannelRespVO> checkChannelList = checkChannelService.getCheckChannelByBase(vo.getId());
            vo.setCheckChannelList(checkChannelList);
            // 查询 最低成本价 与 最低销售价
            List<ProductBasePriceRespVO> basePriceList = basePriceService.queryPriceByBase(vo.getId());
            vo.setBasePriceList(basePriceList);
            BigDecimal minCastPrice = BigDecimal.ZERO;
            BigDecimal minSalePrice = BigDecimal.ZERO;
            List<ProductBasePriceRespVO> list = basePriceList.stream()
                    .filter(price -> !Objects.equals(price.getSpecType(), "free"))
                    .collect(Collectors.toList());
            if (!list.isEmpty()) {
                minCastPrice = list.stream().min(Comparator.comparing(ProductBasePriceRespVO::getCostPrice)).get().getCostPrice();
                minSalePrice = list.stream().min(Comparator.comparing(ProductBasePriceRespVO::getSalePrice)).get().getSalePrice();
            }
            vo.setCostPrice(minCastPrice);
            vo.setSalePrice(minSalePrice);
        });
        return new PageResult<>(iPage.getRecords(), iPage.getTotal());
    }

    @Override
    public PageResult<ProductBaseRespVO> selectBasePage(ProductBasePageReqVO pageReqVO) {
        IPage<ProductBaseRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        IPage<ProductBaseRespVO> iPage = baseMapper.selectProductBasePage(page, pageReqVO);
        iPage.getRecords().forEach(vo -> {
            List<ProductBasePriceRespVO> priceRespVOList = basePriceService.queryPriceByBase(vo.getId());
            vo.setBasePriceList(priceRespVOList);
            BigDecimal minCastPrice = BigDecimal.ZERO;
            BigDecimal minSalePrice = BigDecimal.ZERO;
            List<ProductBasePriceRespVO> list = priceRespVOList.stream()
                    .filter(price -> !Objects.equals(price.getSpecType(), "free"))
                    .collect(Collectors.toList());
            if (!list.isEmpty()) {
                minCastPrice = list.stream().min(Comparator.comparing(ProductBasePriceRespVO::getCostPrice)).get().getCostPrice();
                minSalePrice = list.stream().min(Comparator.comparing(ProductBasePriceRespVO::getSalePrice)).get().getSalePrice();
            }
            vo.setCostPrice(minCastPrice);
            vo.setSalePrice(minSalePrice);
            List<ResourceDO> resourceList = resourceMapper.getListWithoutExcludeId(vo.getId(), null);
            vo.setResourceList(BeanUtils.toBean(resourceList, ResourceSimpleRespVO.class));
        });
        return new PageResult<>(iPage.getRecords(), iPage.getTotal());
    }

    @Override
    public List<ProductBaseRespVO> selectBaseList(ProductBasePageReqVO pageReqVO) {
        IPage<ProductBaseRespVO> page = new Page<>(-1, -1);
        IPage<ProductBaseRespVO> iPage = baseMapper.selectProductBasePage(page, pageReqVO);
        iPage.getRecords().forEach(vo -> {
            List<ResourceDO> resourceList = resourceMapper.getListWithoutExcludeId(vo.getId(), null);
            vo.setResourceList(BeanUtils.toBean(resourceList, ResourceSimpleRespVO.class));

            // 查询 最低成本价 与 最低销售价
            List<ProductBasePriceRespVO> basePriceList = basePriceService.queryPriceByBase(vo.getId());
            vo.setBasePriceList(basePriceList);

        });
        return iPage.getRecords();
    }

    @Override
    public List<ShipRespVO> selectShipList() {
        return baseMapper.selectShipList();
    }

    @Override
    public List<TreeNode<Long>> getProductBaseTreeList() {
        List<ProjectDO> projectList = projectService.getProjectList();
        List<TreeNode<Long>> projectTree = projectList.stream()
                .map(e -> new TreeNode<>(e.getId(), e.getParentId(), e.getName(), e.getSort()))
                .collect(Collectors.toList());
        List<TreeNode<Long>> resultList = new ArrayList<>();
        resultList.addAll(projectTree);
        projectTree.forEach(treeNode -> {
            MPJLambdaWrapper<ProductBaseDO> wrapper = new MPJLambdaWrapperX<ProductBaseDO>()
                    .selectAll(ProductBaseDO.class)
                    .innerJoin(ProjectDO.class, ProjectDO::getId, ProductBaseDO::getProjectId)
                    .eq(ProductBaseDO::getUseStatus, UseStatusEnum.ENABLE.getStatus())
                    .eq(ProductBaseDO::getProjectId, Long.parseLong(treeNode.getId().toString()))
                    .groupBy(ProductBaseDO::getId);
            List<ProductBaseDO> productBaseList = baseMapper.selectJoinList(ProductBaseDO.class, wrapper);
            if (CollUtil.isNotEmpty(productBaseList)) {
                List<TreeNode<Long>> productTreeList = productBaseList.stream().map(e -> new TreeNode<>(e.getId(), e.getProjectId(), e.getName(), null)).collect(Collectors.toList());
                resultList.addAll(productTreeList);
            }
        });
        return resultList;
    }
}