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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.constant.CacheConstant;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.product.dto.ProdGroupDTO;
import com.czg.product.dto.ProductBriefDTO;
import com.czg.product.entity.ProdGroup;
import com.czg.product.entity.ProdGroupRelation;
import com.czg.product.entity.Product;
import com.czg.product.service.ProdGroupService;
import com.czg.product.service.SensitiveOperationService;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ProdGroupMapper;
import com.czg.service.product.mapper.ProdGroupRelationMapper;
import com.czg.service.product.mapper.ProductMapper;
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.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 商品分组
 *
 * @author Tankaikai tankaikai@aliyun.com
 * @since 1.0 2025-02-17
 */
@AllArgsConstructor
@Service
public class ProdGroupServiceImpl extends ServiceImpl<ProdGroupMapper, ProdGroup> implements ProdGroupService {

    private final ProdGroupRelationMapper prodGroupRelationMapper;
    private final ProductMapper productMapper;
    private final SensitiveOperationService sensitiveOperationService;

    private QueryWrapper buildQueryWrapper(ProdGroupDTO param) {
        QueryWrapper queryWrapper = PageUtil.buildSortQueryWrapper();
        if (StrUtil.isNotEmpty(param.getName())) {
            queryWrapper.like(ProdGroup::getName, param.getName());
        }
        Long shopId = StpKit.USER.getShopId(0L);
        queryWrapper.eq(ProdGroup::getShopId, shopId);
        queryWrapper.orderBy(ProdGroup::getSort, true);
        queryWrapper.orderBy(ProdGroup::getId, false);
        return queryWrapper;
    }

    @Override
    public Page<ProdGroupDTO> getProdGroupPage(ProdGroupDTO param) {
        QueryWrapper queryWrapper = buildQueryWrapper(param);
        Page<ProdGroupDTO> page = pageAs(PageUtil.buildPage(), queryWrapper, ProdGroupDTO.class);
        page.getRecords().forEach(group -> {
            List<Long> productIdList = prodGroupRelationMapper.selectObjectListByQueryAs(query()
                    .select(ProdGroupRelation::getProductId).eq(ProdGroupRelation::getProdGroupId, group.getId()), Long.class);
            if (CollUtil.isNotEmpty(productIdList)) {
                List<ProductBriefDTO> productList = productMapper.selectListByQueryAs(query()
                        .select(Product::getId, Product::getCategoryId, Product::getName, Product::getCoverImg)
                        .in(Product::getId, productIdList), ProductBriefDTO.class);
                group.setProductList(productList);
            } else {
                group.setProductList(new ArrayList<>());
            }
        });
        return page;
    }

    @Override
    public List<ProdGroupDTO> getProdGroupList(ProdGroupDTO param) {
        QueryWrapper queryWrapper = buildQueryWrapper(param);
        queryWrapper.eq(ProdGroup::getStatus, SystemConstants.OneZero.ONE);
        return super.listAs(queryWrapper, ProdGroupDTO.class);
    }

    @Override
    public ProdGroupDTO getProdGroupById(Long id) {
        Long shopId = StpKit.USER.getShopId(0L);
        ProdGroupDTO dto = super.getOneAs(query().eq(ProdGroup::getId, id).eq(ProdGroup::getShopId, shopId), ProdGroupDTO.class);
        List<Long> productIdList = prodGroupRelationMapper.selectObjectListByQueryAs(query().select(ProdGroupRelation::getProductId).eq(ProdGroupRelation::getProdGroupId, id), Long.class);
        if (CollUtil.isNotEmpty(productIdList)) {
            List<ProductBriefDTO> productList = productMapper.selectListByQueryAs(query()
                    .select(Product::getId, Product::getCategoryId, Product::getName, Product::getCoverImg)
                    .in(Product::getId, productIdList), ProductBriefDTO.class);
            dto.setProductList(productList);
        } else {
            dto.setProductList(new ArrayList<>());
        }
        return dto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#dto.shopId", allEntries = true)
    public void addProdGroup(ProdGroupDTO dto) {
        Long shopId = StpKit.USER.getShopId(0L);
        boolean exists = super.exists(query().eq(ProdGroup::getName, dto.getName()).eq(ProdGroup::getShopId, shopId));
        if (exists) {
            throw new CzgException("商品分组已存在");
        }
        ProdGroup entity = BeanUtil.copyProperties(dto, ProdGroup.class);
        entity.setShopId(shopId);
        super.save(entity);
        dto.setId(entity.getId());
        Long[] productIds = dto.getProductIds();
        if (ArrayUtil.isNotEmpty(productIds)) {
            int sort = 0;
            for (Long productId : productIds) {
                sort++;
                ProdGroupRelation prodGroupRelation = new ProdGroupRelation();
                prodGroupRelation.setProductId(productId);
                prodGroupRelation.setProdGroupId(entity.getId());
                prodGroupRelation.setSort(sort);
                prodGroupRelationMapper.insert(prodGroupRelation);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#dto.shopId", allEntries = true)
    public void updateProdGroup(ProdGroupDTO dto, boolean isUpdateProduct) {
        Long shopId = StpKit.USER.getShopId(0L);
        dto.setShopId(shopId);
        boolean exists = super.exists(query().eq(ProdGroup::getName, dto.getName()).eq(ProdGroup::getShopId, shopId).ne(ProdGroup::getId, dto.getId()));
        if (exists) {
            throw new CzgException("商品分组已存在");
        }
        ProdGroup entity = getById(dto.getId());
        BeanUtil.copyProperties(dto, entity, CopyOptions.create().setIgnoreNullValue(true));
        if (entity.getUseTime() == SystemConstants.OneZero.ZERO) {
            entity.setSaleStartTime(null);
            entity.setSaleEndTime(null);
        }
        super.updateById(entity, false);
        if (!isUpdateProduct) {
            return;
        }
        prodGroupRelationMapper.deleteByQuery(query().eq(ProdGroupRelation::getProdGroupId, entity.getId()));
        Long[] productIds = dto.getProductIds();
        if (ArrayUtil.isNotEmpty(productIds)) {
            int sort = 0;
            for (Long productId : productIds) {
                sort++;
                ProdGroupRelation prodGroupRelation = new ProdGroupRelation();
                prodGroupRelation.setProductId(productId);
                prodGroupRelation.setProdGroupId(entity.getId());
                prodGroupRelation.setSort(sort);
                prodGroupRelationMapper.insert(prodGroupRelation);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#shopId", allEntries = true)
    public void deleteProdGroup(Long shopId, Long id) {
        super.remove(query().eq(ProdGroup::getId, id).eq(ProdGroup::getShopId, shopId));
        prodGroupRelationMapper.deleteByQuery(query().eq(ProdGroupRelation::getProdGroupId, id));
    }

    @Override
    @CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#shopId", allEntries = true)
    public void disableProdGroup(Long shopId, Long id) {
        UpdateChain.of(ProdGroup.class)
                .set(ProdGroup::getStatus, SystemConstants.OneZero.ZERO)
                .eq(ProdGroup::getId, id)
                .eq(ProdGroup::getShopId, shopId)
                .update();
        ProdGroup prodGroup = mapper.selectOneById(id);
        sensitiveOperationService.send("关闭分组：" + prodGroup.getName());
    }

    @Override
    @CacheEvict(value = {CacheConstant.USER_CLIENT_HOTS_PRODUCT, CacheConstant.USER_CLIENT_GROUPS_PRODUCT}, key = "#shopId", allEntries = true)
    public void enableProdGroup(Long shopId, Long id) {
        UpdateChain.of(ProdGroup.class)
                .set(ProdGroup::getStatus, SystemConstants.OneZero.ONE)
                .eq(ProdGroup::getId, id)
                .eq(ProdGroup::getShopId, shopId)
                .update();
        ProdGroup prodGroup = mapper.selectOneById(id);
        sensitiveOperationService.send("开启分组：" + prodGroup.getName());
    }

}