package cn.ysk.cashier.service.impl.productimpl;

import cn.hutool.core.date.DateUtil;
import cn.ysk.cashier.dto.product.TbProductStocktakinDTO;
import cn.ysk.cashier.dto.product.TbProductStocktakinQueryCriteria;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mapper.product.TbProductMapper;
import cn.ysk.cashier.mapper.product.TbProductStocktakinRepository;
import cn.ysk.cashier.mybatis.mapper.TbProducSkutMapper;
import cn.ysk.cashier.pojo.product.*;
import cn.ysk.cashier.pojo.shop.TbShopInfo;
import cn.ysk.cashier.pojo.shop.TbShopUnit;
import cn.ysk.cashier.repository.product.TbProductRepository;
import cn.ysk.cashier.repository.product.TbProductStockDetailRepository;
import cn.ysk.cashier.repository.product.TbProductStockOperateRepository;
import cn.ysk.cashier.repository.shop.TbShopInfoRepository;
import cn.ysk.cashier.repository.shop.TbShopUnitRepository;
import cn.ysk.cashier.service.product.TbProductStocktakinService;
import cn.ysk.cashier.utils.QueryHelp;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class TbProductStocktakinServiceImpl implements TbProductStocktakinService {
    private final TbShopInfoRepository shopInfoRepository;

    private final TbProducSkutMapper producSkutMapper;

    private final TbProductMapper productMapper;
    private final TbProducSkutMapper tbProducSkutMapper;

    private final TbProductRepository tbProductRepository;

    private final TbProductStocktakinRepository productStocktakinRepository;

    private final TbProductStockOperateRepository tbProductStockOperateRepository;
    private final TbProductStockDetailRepository tbProductStockDetailRepository;

    private final TbShopUnitRepository tbShopUnitRepository;

    public TbProductStocktakinServiceImpl(TbShopInfoRepository shopInfoRepository, TbProducSkutMapper producSkutMapper, TbProductMapper productMapper, TbProducSkutMapper tbProducSkutMapper, TbProductRepository tbProductRepository, TbProductStocktakinRepository productStocktakinRepository, TbProductStockOperateRepository tbProductStockOperateRepository, TbProductStockDetailRepository tbProductStockDetailRepository, TbShopUnitRepository tbShopUnitRepository) {
        this.shopInfoRepository = shopInfoRepository;
        this.producSkutMapper = producSkutMapper;
        this.productMapper = productMapper;
        this.tbProducSkutMapper = tbProducSkutMapper;
        this.tbProductRepository = tbProductRepository;
        this.productStocktakinRepository = productStocktakinRepository;
        this.tbProductStockOperateRepository = tbProductStockOperateRepository;
        this.tbProductStockDetailRepository = tbProductStockDetailRepository;
        this.tbShopUnitRepository = tbShopUnitRepository;
    }


    @Override
    public void addStocktakin(TbProductStocktakinDTO productStocktakinDTO) {
        TbShopInfo shopInfo = shopInfoRepository.findById(productStocktakinDTO.getShopId()).orElse(null);
        if (shopInfo == null) {
            throw new BadRequestException("店铺不存在");
        }

        TbProduct product = tbProductRepository.findById(productStocktakinDTO.getProductId()).orElse(null);
        if (product == null) {
            throw new BadRequestException("商品不存在, 商品id: {}" + productStocktakinDTO.getProductId());
        }

        TbProductStocktakin productStocktakin = new TbProductStocktakin();

        productStocktakin.setProductId(productStocktakinDTO.getProductId());
        productStocktakin.setCreateTime(DateUtil.date());
        productStocktakin.setNote(productStocktakinDTO.getNote());
        productStocktakin.setInventoryStock(productStocktakinDTO.getStocktakinNum());
        productStocktakin.setName(product.getName());
        productStocktakin.setCoverImg(product.getCoverImg());
        productStocktakin.setShopId(Integer.valueOf(product.getShopId()));

        productStocktakinDTO.setPrice(product.getLowPrice());

        // 查询单位
        TbShopUnit tbShopUnit = tbShopUnitRepository.findById(product.getUnitId()).orElse(null);

        int phaseNum;

        long times = Instant.now().toEpochMilli();
        TbProductStockOperate stockOperate = new TbProductStockOperate();
        stockOperate.setShopId(product.getShopId());
        Map<String, String> operatorSnapMap = new HashMap<>();
        operatorSnapMap.put("name", shopInfo.getShopName());
        operatorSnapMap.put("account", shopInfo.getAccount());

        stockOperate.setOperatorSnap(JSON.toJSONString(operatorSnapMap));
        stockOperate.setStockTime(times);
        stockOperate.setCreatedAt(times);
        stockOperate.setUpdatedAt(times);
        stockOperate.setStatus("normal");

        // 保存库存详情
        TbProductStockDetail productStockDetail = new TbProductStockDetail();
        productStockDetail.setCreatedAt(times);
        productStockDetail.setUpdatedAt(times);
        productStockDetail.setIsStock(1);
        int round;
        productStockDetail.setProductId(String.valueOf(product.getId()));
        productStockDetail.setProductName(product.getName());
        productStockDetail.setUnitName(tbShopUnit == null ? null : tbShopUnit.getName());
        productStockDetail.setShopId(String.valueOf(shopInfo.getId()));
        productStockDetail.setSkuId(String.valueOf(productStocktakinDTO.getSkuId()));
        productStockDetail.setSourcePath("NORMAL");
        JSONObject snap = new JSONObject();
        snap.put("coverImg", product.getCoverImg());
        snap.put("productId", product.getId());
        snap.put("name", product.getName());
        snap.put("unitName", tbShopUnit == null ? null : tbShopUnit.getName());
//        snap.put("specSnap", tbShopUnit == null ? null : tbShopUnit.getName());

        // 共享库存
        if (product.getIsDistribute() == 1) {
            phaseNum = productStocktakinDTO.getStocktakinNum() - product.getStockNumber();
            round = (int) Math.floor( product.getStockNumber());
            productStocktakin.setPhasePrice(
                    productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(phaseNum))
            );

            productStockDetail.setSubType(productStocktakinDTO.getStocktakinNum() > product.getStockNumber() ? 1 : -1);
            stockOperate.setType(productStocktakinDTO.getStocktakinNum() > product.getStockNumber() ? "盘点入库" : "盘点出库");
            productStockDetail.setType(productStocktakinDTO.getStocktakinNum() > product.getStockNumber() ? "盘点入库" : "盘点出库");

            productStocktakin.setPhaseNum(productStocktakinDTO.getStocktakinNum() - product.getStockNumber());
            productStocktakin.setStock(product.getStockNumber());
            if (tbProductRepository.updateStock(product.getId(), product.getStockNumber(), productStocktakinDTO.getStocktakinNum()) < 1) {
                throw new BadRequestException("修改库存失败，稍后再试");
            }
            snap.put("stockNumber", product.getStockNumber());

        }else {
            if (productStocktakinDTO.getSkuId() == null) {
                throw new BadRequestException("非共享库存必须传入skuId");
            }

            TbProductSku productSku = producSkutMapper.selectByProIdAndId(productStocktakinDTO.getSkuId(),
                    productStocktakinDTO.getProductId());
            phaseNum = (int) (productStocktakinDTO.getStocktakinNum() - productSku.getStockNumber());

            productStocktakinDTO.setPrice(productSku.getSalePrice());


            round = (int) Math.floor( productSku.getStockNumber());
            productStockDetail.setSpecSnap(productSku.getSpecSnap());

            productStockDetail.setSubType(productStocktakinDTO.getStocktakinNum() > productSku.getStockNumber() ? 1 : -1);
            stockOperate.setType(productStocktakinDTO.getStocktakinNum() > productSku.getStockNumber() ? "盘点入库" : "盘点出库");
            productStockDetail.setType(productStocktakinDTO.getStocktakinNum() > productSku.getStockNumber() ?  "盘点入库" : "盘点出库");
            productStocktakin.setSkuId(productSku.getId());
            productStocktakin.setPhasePrice(
                    productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(phaseNum))
            );
            productStocktakin.setStock(productSku.getStockNumber().intValue());

            productStocktakin.setPhaseNum((int) (productStocktakinDTO.getStocktakinNum() - productSku.getStockNumber()));
            if (producSkutMapper.updateStock(productSku.getId(), productSku.getStockNumber(), productStocktakinDTO.getStocktakinNum()) < 1) {
                throw new BadRequestException("修改库存失败，稍后再试");
            }
            snap.put("stockNumber", productSku.getStockNumber());

        }
        snap.put("number", phaseNum);
        productStocktakin.setPrice(productStocktakinDTO.getPrice());
        productStockDetail.setStockNumber((double) phaseNum);
        productStockDetail.setCostAmount(productStocktakinDTO.getPrice().multiply(BigDecimal.valueOf(Math.abs(phaseNum))));
        JSONArray array = new JSONArray();
        array.add(snap);
        stockOperate.setStockSnap(array.toJSONString());
        productStockDetail.setStockSnap(array.toJSONString());
        productStocktakinRepository.save(productStocktakin);

        TbProductStockOperate saveStockOperate = tbProductStockOperateRepository.save(stockOperate);
        productStockDetail.setLeftNumber(round);
        productStockDetail.setRecordId(saveStockOperate.getId().toString());
        tbProductStockDetailRepository.save(productStockDetail);

    }

    @Override
    public Page<TbProductStocktakin> getPage(TbProductStocktakinQueryCriteria productStocktakinQueryCriteria, Pageable pageable) {
        Page<TbProductStocktakin> page = productStocktakinRepository.findAll((Specification<TbProductStocktakin>) (root, query, criteriaBuilder) -> {
            Predicate predicate = QueryHelp.getPredicate(root, productStocktakinQueryCriteria, criteriaBuilder);
            query.orderBy(criteriaBuilder.desc(root.get("id")));
            return predicate;
        }, pageable);
        return page;
    }
}
