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

import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.dto.product.*;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mybatis.mapper.TbProducSkutMapper;
import cn.ysk.cashier.pojo.product.TbProduct;
import cn.ysk.cashier.pojo.product.TbProductStockDetail;
import cn.ysk.cashier.pojo.shop.TbShopUnit;
import cn.ysk.cashier.repository.order.StockCountRepository;
import cn.ysk.cashier.repository.order.TbOrderInfoRepository;
import cn.ysk.cashier.repository.product.ProductStockCountRepository;
import cn.ysk.cashier.repository.product.TbProductRepository;
import cn.ysk.cashier.repository.shop.TbShopUnitRepository;
import cn.ysk.cashier.utils.*;
import cn.ysk.cashier.vo.TbProductStockCountVo;
import lombok.RequiredArgsConstructor;
import cn.ysk.cashier.repository.product.TbProductStockDetailRepository;
import cn.ysk.cashier.service.product.TbProductStockDetailService;
import cn.ysk.cashier.mapper.product.TbProductStockDetailMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import javax.servlet.http.HttpServletResponse;

@Service
@RequiredArgsConstructor
@Slf4j
public class TbProductStockDetailServiceImpl implements TbProductStockDetailService {

    private final TbProductStockDetailRepository tbProductStockDetailRepository;
    private final TbProductStockDetailMapper tbProductStockDetailMapper;

    private final TbProductRepository tbProductRepository;
    private final TbShopUnitRepository shopUnitRepository;
    private final StockCountRepository stockCountRepository;
    private final ProductStockCountRepository stockRepository;
    private final TbOrderInfoRepository tbOrderInfoRepository;
    private final TbProducSkutMapper skutMapper;


    @Override
    public Map<String,Object> queryAll(TbProductStockDetailQueryCriteria criteria, Pageable pageable){
        Page<TbProductStockDetail> page = tbProductStockDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(tbProductStockDetailMapper::toDto));
    }


    @Override
    public Map<String,Object> queryPage(TbProductStockDetailQueryCriteria criteria) throws ParseException {
        if (criteria.getStartTime() == null || criteria.getEndTime() == null) {
            criteria.setEndTime(new Date());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            criteria.setStartTime(sdf.parse("2024-01-01"));//创建2024年1月1日的Date对象
        }
        if(StringUtils.isNotBlank(criteria.getColumn())){
            switch (criteria.getColumn()){
                case "addCountNumber":
                    criteria.setTypes(Arrays.asList("供应商入库", "盘点入库", "其他入库", "退单"));
                    break;
                case "addNumber":
                    criteria.setTypes(Arrays.asList("供应商入库", "盘点入库", "其他入库"));
                    break;
                case "refundNumber":
                    criteria.setTypes(Collections.singletonList("退单"));
                    break;
                case "subCountNumber":
                    criteria.setTypes(Arrays.asList("供应商出库","其他出库","盘点出库","售出记录","报损"));
                    break;
                case "subNumber":
                    criteria.setTypes(Arrays.asList("供应商出库","其他出库","盘点出库","售出记录"));
                    break;
                case "saleNumber":
                    criteria.setTypes(Collections.singletonList("售出记录"));
                    break;
                case "lossNumber":
                    criteria.setTypes(Collections.singletonList("报损"));
                    break;
                default:
                    criteria.setTypes(Arrays.asList("供应商入库", "盘点入库", "其他入库", "退单","供应商出库","其他出库","盘点出库","售出记录","报损"));
                    break;
            }
        }

        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(criteria.getPage(), criteria.getSize(), sort);

        Page<TbProductStockDetail> page = tbProductStockDetailRepository.findByProductParam(
                criteria.getShopId().toString(), criteria.getProductName(),
                criteria.getCategoryId(),criteria.getType(),
                criteria.getTypes() ,
                criteria.getStartTime().getTime(), criteria.getEndTime().getTime(), pageable);
        Page<TbProductStockDetailDto> map = page.map(tbProductStockDetailMapper::toDto);

        for (TbProductStockDetailDto tbProductStockDetailDto : map.getContent()) {
            if (StrUtil.isNotBlank(tbProductStockDetailDto.getOrderId())) {
                tbOrderInfoRepository.findById(Integer.valueOf(tbProductStockDetailDto.getOrderId())).ifPresent(tbOrderInfo -> tbProductStockDetailDto.setOrderNo(tbOrderInfo.getOrderNo()));
            }
            tbProductStockDetailDto.setTypes();
        }
        Map<String,Object> info = new LinkedHashMap<>(2);
        info.put("content",map.getContent());
        info.put("totalElements",page.getTotalElements());
        return info;
    }

    @Override
    public TbProductStockCountVo stockCount(TbProductStockCountQueryCriteria criteria) throws ParseException {
        if (criteria.getStartTime() == null || criteria.getEndTime() == null) {
            criteria.setEndTime(new Date());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            criteria.setStartTime(sdf.parse("2024-01-01"));//创建2024年1月1日的Date对象
        }
        return stockRepository.productStockCount(criteria.getShopId().toString(), criteria.getProductName(),
                criteria.getCategoryId(),criteria.getType(), criteria.getStartTime().getTime(), criteria.getEndTime().getTime());
    }

    @Override
    public Map<String, Object> stockList(TbProductStockCountQueryCriteria criteria) throws ParseException {
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(criteria.getPage(), criteria.getSize(), sort);
        if (criteria.getStartTime() == null || criteria.getEndTime() == null) {
            criteria.setEndTime(new Date());//
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            criteria.setStartTime(sdf.parse("2024-01-01"));//创建2024年1月1日的Date对象
        }
        Page<TbProductStockListDto> tbProductStockCountDtos = stockRepository.productStock(
                criteria.getShopId().toString(),
                criteria.getProductName(),
                criteria.getCategoryId(),criteria.getType(),
                criteria.getStartTime().getTime(), criteria.getEndTime().getTime(), pageable);
        if (!tbProductStockCountDtos.isEmpty()) {
            tbProductStockCountDtos.getContent().parallelStream().forEach(s-> s.setCountNumber(s.getStockNumber().add(s.getSubCountNumber())));
        }
        return PageUtil.toPage(tbProductStockCountDtos);
    }


    @Override
    public List<TbProductStockDetailDto> queryAll(TbProductStockDetailQueryCriteria criteria){
        return tbProductStockDetailMapper.toDto(tbProductStockDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public TbProductStockDetailDto findById(Long id) {
        TbProductStockDetail tbProductStockDetail = tbProductStockDetailRepository.findById(id).orElseGet(TbProductStockDetail::new);
        ValidationUtil.isNull(tbProductStockDetail.getId(),"TbProductStockDetail","id",id);
        return tbProductStockDetailMapper.toDto(tbProductStockDetail);
    }

    @Override
    public void frmLoss(TbProductFrmLossDto resources) {
        TbProduct product = tbProductRepository.findById(Integer.valueOf(resources.getProductId())).orElse(null);
        if(Objects.isNull(product)){
            throw new BadRequestException("该商品不存在");
        }
        TbShopUnit tbShopUnit = shopUnitRepository.findById(product.getUnitId()).orElse(null);
        TbProductStockDetail stockDetail = new TbProductStockDetail();
        cn.hutool.core.bean.BeanUtil.copyProperties(resources,stockDetail, CopyOptions.create().setIgnoreNullValue(true));
        stockDetail.setLeftNumber(product.getStockNumber());//原库存
        stockDetail.setStockNumber(-stockDetail.getStockNumber());//变动数量
        stockDetail.setSourcePath("CASHIER-APP");
        stockDetail.setProductName(product.getName());
        stockDetail.setUnitName(tbShopUnit==null?"":tbShopUnit.getName());
        stockDetail.setCreatedAt(System.currentTimeMillis());
        stockDetail.setUpdatedAt(System.currentTimeMillis());
        stockDetail.setOperator(SecurityUtils.getCurrentUsername());
        tbProductStockDetailRepository.save(stockDetail);
        product.setStockNumber(product.getStockNumber()-resources.getStockNumber().intValue());
        tbProductRepository.save(product);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TbProductStockDetailDto create(TbProductStockDetail resources) {


        return tbProductStockDetailMapper.toDto(tbProductStockDetailRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(TbProductStockDetail resources) {
        TbProductStockDetail tbProductStockDetail = tbProductStockDetailRepository.findById(resources.getId()).orElseGet(TbProductStockDetail::new);
        ValidationUtil.isNull( tbProductStockDetail.getId(),"TbProductStockDetail","id",resources.getId());
        tbProductStockDetail.copy(resources);
        tbProductStockDetailRepository.save(tbProductStockDetail);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            tbProductStockDetailRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<TbProductStockDetailDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (TbProductStockDetailDto tbProductStockDetail : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("skuId", tbProductStockDetail.getSkuId());
            map.put("商品Id", tbProductStockDetail.getProductId());
            map.put("商品名称", tbProductStockDetail.getProductName());
            map.put("是否开启库存", tbProductStockDetail.getIsStock());
            map.put("规格", tbProductStockDetail.getSpecSnap());
            map.put("商品单位", tbProductStockDetail.getUnitName());
            map.put("店铺Id", tbProductStockDetail.getShopId());
            map.put(" recordId",  tbProductStockDetail.getRecordId());
            map.put("操作批次号", tbProductStockDetail.getBatchNumber());
            map.put("库存操作来源：收银端调用 CASHIER   系统后台调用SHOP", tbProductStockDetail.getSourcePath());
            map.put("关联订单Id", tbProductStockDetail.getOrderId());
            map.put(" 1入库-1出库", tbProductStockDetail.getSubType());
            map.put("purchase采购入库 transfer调拔入库 ", tbProductStockDetail.getType());
            map.put("上次剩余数量", tbProductStockDetail.getLeftNumber());
            map.put("出入库时间", tbProductStockDetail.getStockTime());
            map.put("本次操作库存数量", tbProductStockDetail.getStockNumber());
            map.put("入库合计成本金额", tbProductStockDetail.getCostAmount());
            map.put("出售合计金额", tbProductStockDetail.getSalesAmount());
            map.put("操作人", tbProductStockDetail.getOperator());
            map.put("备注", tbProductStockDetail.getRemark());
            map.put("库存镜像", tbProductStockDetail.getStockSnap());
            map.put(" barCode",  tbProductStockDetail.getBarCode());
            map.put(" coverImg",  tbProductStockDetail.getCoverImg());
            map.put(" createdAt",  tbProductStockDetail.getCreatedAt());
            map.put(" updatedAt",  tbProductStockDetail.getUpdatedAt());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void addSaleRecord(Integer orderId) {
        // 先进行延迟
        CompletableFuture<Void> delayFuture = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(3000L);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(e);
            }
        });

        delayFuture.thenRun(() -> {
            List<StockCountDTO> stockCountDTOS = stockCountRepository.countStockById(orderId);
            log.info("查询到订单id: {}的所有库存数据: {}", orderId, stockCountDTOS);
            stockCountDTOS.forEach(s -> {
                if (s.getProId() > 0) {
                    if (s.getStockCount() > 0) {
                        TbProductStockDetail productStockDetail = new TbProductStockDetail();
                        productStockDetail.setCreatedAt(System.currentTimeMillis());
                        productStockDetail.setUpdatedAt(System.currentTimeMillis());
                        productStockDetail.setShopId(s.getShopId());
                        productStockDetail.setProductId(s.getProId().toString());
                        productStockDetail.setProductName(s.getProName());
                        productStockDetail.setOrderId(orderId.toString());
                        // productStockDetail.setSkuId(s.getSkuId().toString());
                        productStockDetail.setIsStock(s.getIsStock());// 是否开启库存
                        productStockDetail.setLeftNumber(s.getStockNumber() + s.getStockCount());// 原库存
                        productStockDetail.setSpecSnap(s.getSpecSnap());
                        productStockDetail.setUnitName(s.getUnitName());
                        productStockDetail.setStockNumber(-Double.valueOf(s.getStockCount()));
                        productStockDetail.setSourcePath("NORMAL");
                        productStockDetail.setType("售出记录");
                        productStockDetail.setRemark("售出记录:" + orderId);
                        productStockDetail.setSubType(-1);
                        tbProductStockDetailRepository.save(productStockDetail);
                    }
                    skutMapper.incrRealSalesNumber(s.getSkuId().intValue(), s.getStockCount());
                }
            });
        });
    }

}
