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.thread.ThreadUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.czg.exception.CzgException;
import com.czg.product.dto.ConsStockFlowDTO;
import com.czg.product.entity.ConsInfo;
import com.czg.product.entity.ConsStockFlow;
import com.czg.product.enums.InOutItemEnum;
import com.czg.product.enums.InOutTypeEnum;
import com.czg.product.param.ConsCheckStockParam;
import com.czg.product.param.ConsInOutStockHeadParam;
import com.czg.product.param.ConsReportDamageParam;
import com.czg.product.param.ConsStockFlowParam;
import com.czg.product.service.ConsStockFlowService;
import com.czg.product.vo.ConsCheckStockRecordVo;
import com.czg.sa.StpKit;
import com.czg.service.product.mapper.ConsInfoMapper;
import com.czg.service.product.mapper.ConsStockFlowMapper;
import com.czg.service.product.mapper.ProductMapper;
import com.czg.service.product.util.WxAccountUtil;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 耗材库存变动记录
 *
 * @author Tankaikai tankaikai@aliyun.com
 * @since 1.0 2025-02-21
 */
@AllArgsConstructor
@Service
@Slf4j
public class ConsStockFlowServiceImpl extends ServiceImpl<ConsStockFlowMapper, ConsStockFlow> implements ConsStockFlowService {

    private final ConsInfoMapper consInfoMapper;
    private final ProductMapper productMapper;
    @Resource
    private WxAccountUtil wxAccountUtil;

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


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void inStock(ConsInOutStockHeadParam param) {
        Long shopId = StpKit.USER.getShopId(0L);
        Long createUserId = StpKit.USER.getLoginIdAsLong();
        String createUserName = StpKit.USER.getAccount();
        ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class);
        List<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
        List<ConsStockFlow> insertList = new ArrayList<>();
        List<ConsInfo> updateStockList = new ArrayList<>();
        for (ConsStockFlow entity : entityList) {
            BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue());
            entity.setShopId(shopId);
            entity.setInOutType(InOutTypeEnum.IN.value());
            entity.setInOutItem(InOutItemEnum.MANUAL_IN.value());
            entity.setCreateUserId(createUserId);
            entity.setCreateUserName(createUserName);
            Long conId = entity.getConId();
            ConsInfo consInfo = consInfoMapper.selectOneById(conId);
            if (consInfo == null) {
                throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName()));
            }
            entity.setBeforeNumber(consInfo.getStockNumber());
            entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber()));
            insertList.add(entity);
            consInfo.setStockNumber(entity.getAfterNumber());
            updateStockList.add(consInfo);
        }
        super.saveBatch(insertList);
        for (ConsInfo consInfo : updateStockList) {
            consInfoMapper.update(consInfo);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void outStock(ConsInOutStockHeadParam param) {
        Long shopId = StpKit.USER.getShopId(0L);
        Long createUserId = StpKit.USER.getLoginIdAsLong();
        String createUserName = StpKit.USER.getAccount();
        ConsStockFlow head = BeanUtil.copyProperties(param, ConsStockFlow.class);
        List<ConsStockFlow> entityList = BeanUtil.copyToList(param.getBodyList(), ConsStockFlow.class);
        List<ConsStockFlow> insertList = new ArrayList<>();
        List<ConsInfo> updateStockList = new ArrayList<>();
        for (ConsStockFlow entity : entityList) {
            BeanUtil.copyProperties(head, entity, CopyOptions.create().ignoreNullValue());
            entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, entity.getInOutNumber()));
            entity.setShopId(shopId);
            entity.setInOutType(InOutTypeEnum.OUT.value());
            entity.setInOutItem(InOutItemEnum.MANUAL_OUT.value());
            entity.setCreateUserId(createUserId);
            entity.setCreateUserName(createUserName);
            Long conId = entity.getConId();
            ConsInfo consInfo = consInfoMapper.selectOneById(conId);
            if (consInfo == null) {
                throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName()));
            }
            entity.setBeforeNumber(consInfo.getStockNumber());
            entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber()));
            insertList.add(entity);
            consInfo.setStockNumber(entity.getAfterNumber());
            updateStockList.add(consInfo);
        }
        super.saveBatch(insertList);
        for (ConsInfo consInfo : updateStockList) {
            consInfoMapper.update(consInfo);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkStock(ConsCheckStockParam param) {
        Long shopId = StpKit.USER.getShopId(0L);
        Long createUserId = StpKit.USER.getLoginIdAsLong();
        String createUserName = StpKit.USER.getAccount();
        ConsStockFlow entity = new ConsStockFlow();
        entity.setCreateUserId(createUserId);
        entity.setCreateUserName(createUserName);
        entity.setShopId(shopId);
        entity.setConId(param.getConId());
        entity.setConName(param.getConName());
        entity.setPurchasePrice(param.getPrice());
        ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId());
        if (consInfo == null) {
            throw new CzgException(StrUtil.format("耗材{}不存在", entity.getConName()));
        }
        BigDecimal winLossNumber = NumberUtil.sub(param.getActualNumber(), param.getStockNumber());
        if (!NumberUtil.equals(winLossNumber, param.getWinLossNumber())) {
            throw new CzgException(StrUtil.format("耗材{}库存在发生变动，请刷新后重试", entity.getConName()));
        }
        entity.setBeforeNumber(consInfo.getStockNumber());
        entity.setInOutNumber(winLossNumber);
        entity.setAfterNumber(NumberUtil.add(entity.getBeforeNumber(), entity.getInOutNumber()));
        if (NumberUtil.isLess(winLossNumber, BigDecimal.ZERO)) {
            entity.setInOutType(InOutTypeEnum.OUT.value());
            entity.setInOutItem(InOutItemEnum.LOSS_OUT.value());
        } else {
            entity.setInOutType(InOutTypeEnum.IN.value());
            entity.setInOutItem(InOutItemEnum.WIN_IN.value());
        }
        entity.setSubTotal(NumberUtil.mul(winLossNumber, param.getPrice()));
        entity.setRemark(param.getRemark());
        saveFlow(entity);
        consInfo.setStockNumber(entity.getAfterNumber());
        consInfoMapper.update(consInfo);
    }

    @Override
    public Page<ConsCheckStockRecordVo> getCheckStockRecordPage(Long conId) {
        Long shopId = StpKit.USER.getShopId(0L);
        return super.pageAs(PageUtil.buildPage(), query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class);
    }

    @Override
    public List<ConsCheckStockRecordVo> getCheckStockRecordList(Long conId) {
        Long shopId = StpKit.USER.getShopId(0L);
        return super.mapper.selectListByQueryAs(query().eq(ConsStockFlow::getShopId, shopId).eq(ConsStockFlow::getConId, conId).orderBy(ConsStockFlow::getId, false), ConsCheckStockRecordVo.class);
    }

    @Override
    public void reportDamage(ConsReportDamageParam param) {
        Long shopId = StpKit.USER.getShopId(0L);
        Long createUserId = StpKit.USER.getLoginIdAsLong();
        String createUserName = StpKit.USER.getAccount();
        ConsInfo consInfo = consInfoMapper.selectOneById(param.getConId());
        if (consInfo == null) {
            throw new CzgException("耗材不存在");
        }
        ConsStockFlow entity = new ConsStockFlow();
        entity.setCreateUserId(createUserId);
        entity.setCreateUserName(createUserName);
        entity.setShopId(shopId);
        entity.setConId(param.getConId());
        entity.setConName(consInfo.getConName());
        entity.setPurchasePrice(consInfo.getPrice());
        BigDecimal balance = NumberUtil.sub(consInfo.getStockNumber(), param.getNumber());
        if (NumberUtil.isLess(balance, BigDecimal.ZERO)) {
            throw new CzgException(StrUtil.format("耗材{}报损数量不能大于当前库存{}", entity.getConName(), consInfo.getStockNumber()));
        }
        entity.setBeforeNumber(consInfo.getStockNumber());
        entity.setInOutNumber(NumberUtil.sub(BigDecimal.ZERO, param.getNumber()));
        entity.setAfterNumber(balance);
        entity.setInOutType(InOutTypeEnum.OUT.value());
        entity.setInOutItem(InOutItemEnum.DAMAGE_OUT.value());
        entity.setSubTotal(NumberUtil.mul(param.getNumber(), consInfo.getPrice()));
        entity.setImgUrls(JSON.toJSONString(param.getImgUrls()));
        saveFlow(entity);
        consInfo.setStockNumber(entity.getAfterNumber());
        consInfoMapper.update(consInfo);
    }

    @Override
    public Page<ConsStockFlowDTO> findConsStockFlowPage(ConsStockFlowParam param) {
        Long shopId = StpKit.USER.getShopId(0L);
        PageHelper.startPage(PageUtil.buildPageHelp());
        return PageUtil.convert(new PageInfo<>(mapper.findConsStockFlowPage(shopId, param.getInOutType(), param.getInOutItem(), param.getConId())));
    }

    @Override
    public void saveFlow(ConsStockFlow entity) {
        super.save(entity);
        Long shopId = entity.getShopId();
        BigDecimal afterNumber = entity.getAfterNumber();
        ConsInfo consInfo = consInfoMapper.selectOneById(entity.getConId());
        String shopName = "";
        try {
            shopName = StpKit.USER.getShopName();
        } catch (Exception e) {
            log.error("获取店铺名称失败");
        }
        if (StrUtil.isEmpty(shopName)) {
            shopName = productMapper.getShopName(shopId);
        }
        BigDecimal conWarning = consInfo.getConWarning();
        // 库存小于警告值，发送消息提醒
        if (NumberUtil.isLess(afterNumber, conWarning)) {
            List<String> openIdList = consInfoMapper.findOpenIdList(shopId, "con");
            if (CollUtil.isEmpty(openIdList)) {
                return;
            }
            String conName = StrUtil.format("{}数量<预警值{}", consInfo.getConName(), conWarning);
            String finalShopName = shopName;
            ThreadUtil.execAsync(() -> {
                openIdList.parallelStream().forEach(openId -> {
                    wxAccountUtil.sendStockMsg(finalShopName, conName, afterNumber, openId);
                });
            });
        }
    }

}
