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

import cn.hutool.core.bean.copier.CopyOptions;
import cn.ysk.cashier.cons.domain.TbConsInfo;
import cn.ysk.cashier.cons.domain.TbConsInfoFlow;
import cn.ysk.cashier.cons.domain.TbConsStockCountQueryCriteria;
import cn.ysk.cashier.cons.repository.TbConsInfoFlowRepository;
import cn.ysk.cashier.cons.repository.TbConsInfoRepository;
import cn.ysk.cashier.cons.service.TbConsInfoFlowService;
import cn.ysk.cashier.cons.service.dto.TbConsInfoFlowDto;
import cn.ysk.cashier.cons.service.dto.TbConsInfoFlowQueryCriteria;
import cn.ysk.cashier.cons.service.mapstruct.TbConsInfoFlowMapper;
import cn.ysk.cashier.dto.product.TbProductStockCountQueryCriteria;
import cn.ysk.cashier.dto.product.TbProductStockListDto;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.repository.product.ProductStockCountRepository;
import cn.ysk.cashier.utils.*;
import cn.ysk.cashier.vo.TbProductStockCountVo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@RequiredArgsConstructor
public class TbConsInfoFlowServiceImpl implements TbConsInfoFlowService {

    private final TbConsInfoFlowRepository tbConsInfoFlowRepository;
    private final TbConsInfoRepository consInfoRepository;
    private final TbConsInfoFlowMapper tbConsInfoFlowMapper;
    private final ProductStockCountRepository stockRepository;

    @Override
    public Map<String,Object> queryAll(TbConsInfoFlowQueryCriteria criteria, Pageable pageable){

        criteria.setAmount(BigDecimal.ZERO);
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), sort);
        Page<TbConsInfoFlow> page = tbConsInfoFlowRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);

       page.get().forEach(it->{
          String name=  tbConsInfoFlowRepository.selectByPskId(it.getProSkuId());
          if(Objects.nonNull(name)){
              it.setProductName(name);
          }
       });

        return PageUtil.toPage(page.map(tbConsInfoFlowMapper::toDto));
    }

    @Override
    public List<TbConsInfoFlowDto> queryAll(TbConsInfoFlowQueryCriteria criteria){
        return tbConsInfoFlowMapper.toDto(tbConsInfoFlowRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }


    //增加数量addCountNumber;  stockIn cancelCart init stockIn checkStockIn
    //手动增加addNumber;    checkStockIn stockOtherIn
    //退货refundNumber;   cancelCart
    //减少数量subCountNumber; createCart  stockout  checkStockOut
    //手动减少subNumber;    checkStockOut
    //销售量/消耗saleNumber; createCart
    //报损lossNumber;     frmLoss
    //入库stockInNumber;  stockIn
    //出库stockOutNumber; stockout
    @Override
    public Map<String,Object> queryPage(TbConsStockCountQueryCriteria 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.setBizCode(Arrays.asList("stockIn","cancelCart","init","stockIn","checkStockIn"));
                    break;
                case "addNumber":
                    criteria.setBizCode(Arrays.asList("checkStockIn", "stockOtherIn"));
                    break;
                case "refundNumber":
                    criteria.setBizCode(Collections.singletonList("cancelCart"));
                    break;
                case "subCountNumber":
                    criteria.setBizCode(Arrays.asList("createCart","stockout","checkStockOut"));
                    break;
                case "subNumber":
                    criteria.setBizCode(Collections.singletonList("checkStockOut"));
                    break;
                case "saleNumber":
                    criteria.setBizCode(Collections.singletonList("createCart"));
                    break;
                case "lossNumber":
                    criteria.setBizCode(Collections.singletonList("frmLoss"));
                    break;
                case "stockInNumber":
                    criteria.setBizCode(Collections.singletonList("stockIn"));
                    break;
                case "stockOutNumber":
                    criteria.setBizCode(Collections.singletonList("stockout"));
                    break;
                default:
                    criteria.setBizCode(Arrays.asList("stockIn","cancelCart","init","stockIn","checkStockIn","stockOtherIn","cancelCart","createCart","stockout","checkStockOut","frmLoss"));
                    break;
            }
        }
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(criteria.getPage(), criteria.getSize(), sort);
        Page<TbConsInfoFlow> page = tbConsInfoFlowRepository.findByConsParam(
                criteria.getShopId(), criteria.getConsId(), criteria.getConName(),criteria.getConTypeId(),
                criteria.getBizCode(),criteria.getStartTime(),criteria.getEndTime(),pageable);
        return PageUtil.toPage(page);
    }

    @Override
    public TbProductStockCountVo stockCount(TbConsStockCountQueryCriteria 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.consStockCount(criteria.getShopId(), criteria.getConsId(), criteria.getConName(),
                criteria.getConTypeId(), criteria.getStartTime(), criteria.getEndTime());
    }

    @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> stockCountDtos = stockRepository.consStock(
                criteria.getShopId().toString(),
                criteria.getProductName(),
                criteria.getCategoryId(),
                DateUtil.getStrTime(criteria.getStartTime()), DateUtil.getStrTime(criteria.getEndTime()), pageable);
        if (!stockCountDtos.isEmpty()) {
            stockCountDtos.getContent().parallelStream().forEach(s-> s.setCountNumber(s.getStockNumber().add(s.getSubCountNumber())));
        }
        return PageUtil.toPage(stockCountDtos);
    }

    @Override
    public void frmLoss(TbConsInfoFlowDto resources) {
        TbConsInfo tbConsInfo = consInfoRepository.findById(resources.getConsId()).orElse(null);
        if(Objects.isNull(tbConsInfo)){
            throw new BadRequestException("该耗材不存在");
        }
        BigDecimal balance = tbConsInfo.getStockNumber().subtract(resources.getAmount());
        TbConsInfoFlow tbConsInfoFlow = new TbConsInfoFlow();
        cn.hutool.core.bean.BeanUtil.copyProperties(resources,tbConsInfoFlow, CopyOptions.create().setIgnoreNullValue(true));
        tbConsInfoFlow.setConName(tbConsInfo.getConName());
        tbConsInfoFlow.setBalance(balance);
        tbConsInfoFlow.setBizCode("frmLoss");
        tbConsInfoFlow.setBizName("报损");
        tbConsInfoFlow.setBizType("-");
        tbConsInfoFlow.setCreateTime(new Timestamp(System.currentTimeMillis()));
        tbConsInfoFlow.setOperator(SecurityUtils.getCurrentUsername());
        tbConsInfoFlowRepository.save(tbConsInfoFlow);
        tbConsInfo.setStockNumber(balance);
        consInfoRepository.save(tbConsInfo);
    }

    @Override
    @Transactional
    public TbConsInfoFlowDto findById(Integer id) {
        TbConsInfoFlow tbConsInfoFlow = tbConsInfoFlowRepository.findById(id).orElseGet(TbConsInfoFlow::new);
        ValidationUtil.isNull(tbConsInfoFlow.getId(),"TbConsInfoFlow","id",id);
        return tbConsInfoFlowMapper.toDto(tbConsInfoFlow);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TbConsInfoFlowDto create(TbConsInfoFlow resources) {
        return tbConsInfoFlowMapper.toDto(tbConsInfoFlowRepository.save(resources));
    }

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

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

    @Override
    public void download(List<TbConsInfoFlowDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (TbConsInfoFlowDto tbConsInfoFlow : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("耗材id", tbConsInfoFlow.getConsId());
            map.put("耗材名称", tbConsInfoFlow.getConName());
            map.put("变化值", tbConsInfoFlow.getAmount());
            map.put("变化后的值", tbConsInfoFlow.getBalance());
            map.put("操作代码", tbConsInfoFlow.getBizCode());
            map.put("操作说明", tbConsInfoFlow.getBizName());
            map.put("加减标识+/-", tbConsInfoFlow.getBizType());
            map.put(" createTime",  tbConsInfoFlow.getCreateTime());
            map.put(" updateTime",  tbConsInfoFlow.getUpdateTime());
            map.put("店铺id", tbConsInfoFlow.getShopId());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}