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

import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.dto.product.OutAndOnDto;
import cn.ysk.cashier.dto.product.StockQueryDto;
import cn.ysk.cashier.dto.product.TbProductDto;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.pojo.product.TbProduct;
import cn.ysk.cashier.pojo.product.TbProductSku;
import cn.ysk.cashier.pojo.product.TbProductStockDetail;
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.TbProductSkuRepository;
import cn.ysk.cashier.repository.product.TbProductStockDetailRepository;
import cn.ysk.cashier.repository.shop.TbShopInfoRepository;
import cn.ysk.cashier.repository.shop.TbShopUnitRepository;
import cn.ysk.cashier.service.TbProductStockOperateService;
import cn.ysk.cashier.service.product.StockService;
import cn.ysk.cashier.service.product.TbProductService;
import cn.ysk.cashier.utils.*;
import cn.ysk.cashier.vo.StockUpdateValueVO;
import cn.ysk.cashier.vo.StockUpdateWarnLineVO;
import cn.ysk.cashier.vo.StockV2Vo;
import cn.ysk.cashier.vo.StockVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class StockServiceImpl implements StockService {

    private final TbProductSkuRepository tbProductSkuRepository;
    private final TbProductService productService;
    private final RedisUtils redisUtils;


    private final TbProductStockOperateService stockOperateService;
    private final TbProductSkuRepository skuRepository;
    private final TbShopInfoRepository tbShopInfoRepository;
    private final TbShopUnitRepository shopUnitRepository;
    private final TbProductStockDetailRepository tbProductStockDetailRepository;
    private final TbProductRepository tbProductRepository;
    private final WxMsgUtils wxMsgUtils;

    @PersistenceContext
    private EntityManager em;

    @Override
    public Page queryAll(StockQueryDto criteria, Integer page, Integer size) {
        Pageable pageable = PageRequest.of(page, size);
        return tbProductSkuRepository.searchProStock(criteria.getShopId(), criteria.getName(), criteria.getIsStock(), criteria.getNum(), pageable);
    }

    @Override
    public Page queryAllV2(StockQueryDto criteria, Integer page, Integer size) {
        Pageable pageable = PageRequest.of(page, size);
        if (StrUtil.isNotBlank(criteria.getSort()) && Boolean.parseBoolean(criteria.getSort())) {
            return tbProductSkuRepository.searchProStockV2ByDesc(criteria.getShopId(), criteria.getName(), criteria.getIsStock(), criteria.getCategoryId(),  pageable);
        }
        return tbProductSkuRepository.searchProStockV2(criteria.getShopId(), criteria.getName(), criteria.getIsStock(), criteria.getCategoryId(),  pageable);
    }

    @Override
    public List<StockV2Vo> queryProductSku(String productId) {
        return tbProductSkuRepository.searchProductSkuByProductId(productId);
    }

    @Override
    public void download(StockQueryDto criteria, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        List<StockVo> stockVos = tbProductSkuRepository.searchProStock(criteria.getShopId(), criteria.getName(), criteria.getIsStock(), criteria.getNum());
        for (StockVo all : stockVos) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id(如需导入,该值不可变)", all.getId());
            map.put("商品名称", all.getName());
            map.put("商品类型", all.getType());
            map.put("商品规格", all.getSpecSnap());
            map.put("商品单位", all.getUnitName());
            map.put("库存数量", all.getNumber());
//            map.put("库存开关", all.getIsStock().equals(0)?"否":"是");
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void downloadV2(StockQueryDto summaryDto, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        List<StockV2Vo> stockVos = tbProductSkuRepository.searchProStockV2(summaryDto.getShopId(), summaryDto.getName(),
                summaryDto.getIsStock(), summaryDto.getCategoryId());
        for (StockV2Vo all : stockVos) {
            if (all.getIsDistribute().equals(1)) {
                Map<String, Object> map = new LinkedHashMap<>();
                map.put("id(如需导入,该值不可变)", all.getProId());
                map.put("商品名称", all.getName());
                map.put("商品skuId(如需导入,该值不可变)", all.getSkuId());
                map.put("商品类型", all.getType());
                map.put("商品规格", all.getSpecSnap());
                map.put("商品单位", all.getUnitName());
                map.put("库存数量", all.getStockNumber());
                map.put("库存开关", all.getIsStock().equals(0) ? "否" : "是");
                map.put("是否共享库存", all.getIsDistribute().equals(0) ? "否" : "是");
                map.put("是否售罄", all.getIsPauseSale().equals(0) ? "否" : "是");
                list.add(map);
            } else {
                List<StockV2Vo> skuList = queryProductSku(all.getProId().toString());
                for (StockV2Vo sku : skuList) {
                    Map<String, Object> skuMap = new LinkedHashMap<>();
                    skuMap.put("id(如需导入,该值不可变)", "sku");
                    skuMap.put("商品名称", all.getName());
                    skuMap.put("商品skuId(如需导入,该值不可变)", sku.getSkuId());
                    skuMap.put("商品类型", sku.getType());
                    skuMap.put("商品规格", sku.getSpecSnap());
                    skuMap.put("商品单位", sku.getUnitName());
                    skuMap.put("库存数量", sku.getStockNumber());
                    skuMap.put("库存开关", sku.getIsStock().equals(0) ? "否" : "是");
                    skuMap.put("是否共享库存", sku.getIsDistribute().equals(0) ? "否" : "是");
                    skuMap.put("是否售罄", sku.getIsPauseSale().equals(0) ? "否" : "是");
                    list.add(skuMap);
                }
            }
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void importExcel(String shopId, MultipartFile file) throws IOException {
        //根据路径获取这个操作excel的实例
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file.getInputStream());
        //根据页面index 获取sheet页
        XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
        XSSFRow row = null;
        List<StockVo> list = new ArrayList<>();
        for (int i = 1; i < sheet.getPhysicalNumberOfRows(); i++) {
            row = sheet.getRow(i);
            if (row != null) {
                if (row.getCell(0) != null) {
                    Optional<TbProductSku> byId = skuRepository.findById(Integer.valueOf(row.getCell(0).toString()));
                    if (byId.isPresent()) {
                        TbProductSku sku = byId.get();
                        list.add(new StockVo(
                                sku.getId(),
                                row.getCell(1).toString(),
                                row.getCell(4).toString(),
                                row.getCell(3).toString(),
                                row.getCell(5).toString(),
                                sku.getStockNumber()));
                    }
                }
            }
        }
        log.info("库存导入.importExcel.data:" + list);
        OutAndOnDto outAndOnDto = new OutAndOnDto();
        outAndOnDto.setShopId(shopId);
        outAndOnDto.setList(new ArrayList<>(list));
        outAndOnDto.setType("purchase");
        outAndOnDto.setRemark("一次性导入 库存数会覆盖");
        outAndOnDto.setIsImport("true");
        outAndOnDto.setTime(System.currentTimeMillis());
        outAndOnDto.setTotalAmount(BigDecimal.ZERO);
        outAndOnDto.setPaidAmount(BigDecimal.ZERO);
        stockOperateService.createOutAndONOperate(outAndOnDto);
        inHouse(shopId, list);
    }

    @Override
    @Transactional
    public void importExcelV2(String shopId, MultipartFile file) throws IOException {
        //根据路径获取这个操作excel的实例
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file.getInputStream());
        //根据页面index 获取sheet页
        XSSFSheet sheet = xssfWorkbook.getSheetAt(0);
        XSSFRow row = null;
        List<StockV2Vo> list = new ArrayList<>();

        List<TbProductStockDetail> stockDetails = new ArrayList<>();

        for (int i = 1; i < sheet.getPhysicalNumberOfRows(); i++) {
            row = sheet.getRow(i);
            if (row != null) {
                XSSFCell cell0 = row.getCell(0);
                String productIdStr = cell0.toString();

                TbProductStockDetail stockDetail = new TbProductStockDetail();
                stockDetail.setCreatedAt(System.currentTimeMillis());
                stockDetail.setUpdatedAt(System.currentTimeMillis());
                stockDetail.setSourcePath("NORMAL");
                stockDetail.setType("一次性入库覆盖库存");
                stockDetail.setSubType(1);
                stockDetail.setRemark("一次性入库覆盖库存");

                if ("sku".equals(productIdStr)) {
                    Optional<TbProductSku> byId = skuRepository.findById(Double.valueOf(row.getCell(2).toString()).intValue());
                    if (byId.isPresent()) {
                        TbProductSku sku = byId.get();

                        String numStr = row.getCell(6).toString();
                        Double aDouble = Double.valueOf(numStr);
                        if (aDouble.equals(sku.getStockNumber())) {
                            continue;
                        }

                        TbProductDto product = productService.findById(Integer.valueOf(sku.getProductId()));
                        TbShopUnit shopUnit = shopUnitRepository.searchUnit(product.getUnitId());

                        stockDetail.setShopId(sku.getShopId());
                        stockDetail.setSkuId(sku.getId().toString());
                        stockDetail.setProductId(product.getId().toString());
                        stockDetail.setProductName(product.getName());
                        stockDetail.setUnitName(shopUnit.getName());
                        stockDetail.setLeftNumber(0);
                        stockDetail.setStockNumber(aDouble);
                        stockDetails.add(stockDetail);

                        list.add(new StockV2Vo(
                                0,
                                sku.getId(),
                                row.getCell(1).toString(),
                                row.getCell(5).toString(),
                                row.getCell(4).toString(),
                                aDouble.intValue(),
                                sku.getStockNumber().intValue(),
                                0
                        ));
                    }
                } else {
                    TbProductDto product = productService.findById(Double.valueOf(productIdStr).intValue());
                    if (product != null) {
                        String numStr = row.getCell(6).toString();
                        Double aDouble = Double.valueOf(numStr);
                        Integer aIntValue = aDouble.intValue();
                        if (aIntValue.equals(product.getStockNumber())) {
                            continue;
                        }

                        TbShopUnit shopUnit = shopUnitRepository.searchUnit(product.getUnitId());

                        stockDetail.setShopId(product.getShopId());
                        stockDetail.setProductId(product.getId().toString());
                        stockDetail.setProductName(product.getName());
                        stockDetail.setUnitName(shopUnit.getName());
                        stockDetail.setLeftNumber(0);
                        stockDetail.setStockNumber(aDouble);
                        stockDetails.add(stockDetail);

                        list.add(new StockV2Vo(
                                product.getId(),
                                0,
                                product.getName(),
                                row.getCell(5).toString(),
                                row.getCell(4).toString(),
                                aIntValue,
                                product.getStockNumber(),
                                product.getIsDistribute()
                        ));
                    }
                }
            }
        }

        if (!stockDetails.isEmpty()) {
            tbProductStockDetailRepository.saveAll(stockDetails);
        }

        log.info("库存导入.importExcel.data:" + list);
        OutAndOnDto outAndOnDto = new OutAndOnDto();
        outAndOnDto.setShopId(shopId);
        outAndOnDto.setList(new ArrayList<>(list));
        outAndOnDto.setType("purchase");
        outAndOnDto.setRemark("一次性导入 库存数会覆盖");
        outAndOnDto.setIsImport("true");
        outAndOnDto.setTime(System.currentTimeMillis());
        outAndOnDto.setTotalAmount(BigDecimal.ZERO);
        outAndOnDto.setPaidAmount(BigDecimal.ZERO);
        stockOperateService.createOutAndONOperate(outAndOnDto);
        inHouseV2(shopId, list);
    }

    @Override
    @Transactional
    public void inHouse(String shopId, List<StockVo> list) {
        Map<Integer, Double> idStockMap = new HashMap<>();
        for (StockVo stockVo : list) {
            tbProductSkuRepository.updateStockNumber2(stockVo.getId(), shopId, Double.parseDouble(stockVo.getNumber().toString()));
            idStockMap.put(stockVo.getId(), Double.parseDouble(stockVo.getNumber().toString()));
        }
        redisUtils.redisUp(2, shopId, idStockMap);
    }

    @Transactional
    public void inHouseV2(String shopId, List<StockV2Vo> list) {
        Set<Integer> proIds = new HashSet<>();
        Set<Integer> skuIds = new HashSet<>();
        for (StockV2Vo stockVo : list) {
            if (stockVo.getProId() == 0) {
                tbProductSkuRepository.updateStockNumber2(stockVo.getSkuId(), shopId, Double.parseDouble(stockVo.getNumber().toString()));
                skuIds.add(stockVo.getSkuId());
            } else {
                productService.updateStockNumber(stockVo.getProId(), Double.parseDouble(stockVo.getNumber().toString()));
                proIds.add(stockVo.getProId());
            }
        }
        redisUtils.delByIntKey(CacheKey.PRODUCT_SKU + shopId + ":product", proIds);
        redisUtils.delByIntKey(CacheKey.PRODUCT_SKU + shopId + ":", skuIds);
    }

    @Transactional
    @Override
    public void updateIsStock(Integer proId, String shopId, Integer isStock) {
        productService.updateIsStock(proId, shopId, isStock);
    }

    @Override
    @Transactional
    public void updateProductStatus(StockUpdateValueVO updateValueVO) {
        if (!"0".equals(updateValueVO.getUpdateValue()) && !"1".equals(updateValueVO.getUpdateValue())) {
            throw new BadRequestException("无效值");
        }
        if (StringUtils.isBlank(updateValueVO.getTargetId())) {
            throw new BadRequestException("更新id不能为空");
        }
        StringBuilder sqlQuery = new StringBuilder("update tb_product ");

        switch (updateValueVO.getUpdateKey()) {
            case "pauseSaleSku":
                sqlQuery = new StringBuilder("update tb_product_sku set is_pause_sale = ").
                        append(updateValueVO.getUpdateValue()).
                        append(" where id = ").
                        append(updateValueVO.getTargetId()).
                        append(";");

                Query nativeQuery = em.createNativeQuery(String.valueOf(sqlQuery));
                nativeQuery.executeUpdate();

                TbProduct product = tbProductRepository.selectBySkuId(Integer.valueOf(updateValueVO.getTargetId()));
                TbProductSku tbProductSku = tbProductSkuRepository.findById(Integer.valueOf(updateValueVO.getTargetId())).orElse(null);
                // 推送微信操作消息
                if (product != null && tbProductSku != null) {
                    wxMsgUtils.aboardOperationMsg(("0".equals(updateValueVO.getUpdateValue()) ? "关闭售罄: " : "开启售罄: ") + product.getName() + "/"+ tbProductSku.getSpecSnap(), Integer.valueOf(updateValueVO.getShopId()));
                }else {
                    log.warn("推送微信操作消息失败，未查询到商品信息，skuId: {}", updateValueVO.getTargetId());
                }
                return;
            case "stock":
                sqlQuery.append(" set is_stock = ").append(updateValueVO.getUpdateValue());
                break;
            case "distribute":
                sqlQuery.append(" set is_distribute = ").append(updateValueVO.getUpdateValue());
                break;
            case "pauseSale":
                sqlQuery.append(" set is_pause_sale = ").append(updateValueVO.getUpdateValue());
                TbProduct product1 = tbProductRepository.getById(Integer.valueOf(updateValueVO.getTargetId()));

                // 推送微信操作消息
                if (product1 != null) {
                    wxMsgUtils.aboardOperationMsg(("0".equals(updateValueVO.getUpdateValue()) ? "关闭售罄: " : "开启售罄: ") + product1.getName(), Integer.valueOf(updateValueVO.getShopId()));
                }else {
                    log.warn("推送微信操作消息失败，未查询到商品信息，skuId: {}", updateValueVO.getTargetId());
                }
                break;
            default:
                throw new BadRequestException("无效更新类型");
        }

        sqlQuery.append(" where ");

        if (StringUtils.isNotBlank(updateValueVO.getShopId())) {
            sqlQuery.append(" shop_id = ").append(updateValueVO.getShopId());
            sqlQuery.append(" and ");
        }
        sqlQuery.append(" id = ").append(updateValueVO.getTargetId());

        sqlQuery.append(" ;");
        System.out.println(sqlQuery);

        Query nativeQuery = em.createNativeQuery(String.valueOf(sqlQuery));
        nativeQuery.executeUpdate();
    }

    @Override
    public void updateProductWarnLine(StockUpdateWarnLineVO stockUpdateWarnLineVO) {
        TbShopInfo shopInfo = tbShopInfoRepository.findById(Integer.valueOf(stockUpdateWarnLineVO.getShopId())).orElse(null);
        if (shopInfo == null) {
            throw new BadRequestException("店铺不存在");
        }
        tbProductSkuRepository.updateWarnLineByShopId(stockUpdateWarnLineVO.getWarnLine(), stockUpdateWarnLineVO.getShopId());
    }

    @Override
    public void grounding(Integer shopId, Integer skuId, Boolean isGrounding) {
        TbProductSku tbProductSku = skuRepository.findById(skuId).orElse(null);
        if (tbProductSku == null) {
            throw new BadRequestException("商品不存在，skuId: " + skuId);
        }

        TbProduct product = tbProductRepository.selectByShopIdAndId(Integer.parseInt(tbProductSku.getProductId()), String.valueOf(shopId));
        // 推送微信操作消息
        wxMsgUtils.aboardOperationMsg((isGrounding ? "上架商品: " : "下架商品: ") + product.getName(), shopId);
        // 共享库存下架所有sku
        if (product.getIsDistribute().equals(1)) {
            tbProductSkuRepository.updateGroundingByProId(product.getId().toString(), isGrounding ? 1 : 0);
        }else {
            tbProductSkuRepository.updateGrounding(skuId, isGrounding ? 1 : 0);
        }
    }
}
