package com.neusoft.smart.pos.inventory.service;

import com.neusoft.smart.pos.dto.inventory.request.InventoryConfigRequest;
import com.neusoft.smart.pos.dto.inventory.request.InventoryStoreHistoryRequest;
import com.neusoft.smart.pos.dto.inventory.request.InventoryStoreRequest;
import com.neusoft.smart.pos.dto.inventory.response.InventoryGoodsConfigResponse;
import com.neusoft.smart.pos.dto.inventory.response.InventoryStoreHistoryResponse;
import com.neusoft.smart.pos.dto.inventory.response.InventoryStoreResponse;
import com.neusoft.smart.pos.dto.inventory.response.InventoryTotalAmountResponse;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.BeanUtil;
import com.neusoft.smart.pos.framework.utils.DateUtils;
import com.neusoft.smart.pos.framework.utils.ExcelUtils;
import com.neusoft.smart.pos.inventory.constants.GoodsErrorCode;
import com.neusoft.smart.pos.inventory.persistent.domain.InventoryGoodsConfig;
import com.neusoft.smart.pos.inventory.persistent.domain.InventoryGoodsConfigExample;
import com.neusoft.smart.pos.inventory.persistent.domain.InventoryStoreHistoryExample;
import com.neusoft.smart.pos.inventory.persistent.domain.InventoryStoreTotal;
import com.neusoft.smart.pos.inventory.persistent.domain.InventoryStoreTotalExample;
import com.neusoft.smart.pos.inventory.persistent.domain.InventoryTotalAmount;
import com.neusoft.smart.pos.inventory.persistent.mapper.InventoryGoodsConfigMapper;
import com.neusoft.smart.pos.inventory.persistent.mapper.InventoryStoreMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.stream.Collectors;

@Service("inventoryStoreService")
public class InventoryStoreService {
    
    @Resource
    private InventoryStoreMapper storeMapper;
    
    @Resource
    private InventoryGoodsConfigMapper inventoryGoodsConfigMapper;
    
    public InventoryStoreResponse getList(InventoryStoreRequest request) {
        InventoryStoreTotalExample example = new InventoryStoreTotalExample();
        
        if (StringUtils.isEmpty(request.getShopId())) {
            throw new BusinessCommonException(GoodsErrorCode.MISSING_STORE_ID);
        }
        example.setShopId(request.getShopId());
        example.setOrderByClause("goods_id desc");
        
        if (request.getIsPage() == null || request.getIsPage())
            example.page(request.getOffset(), request.getLimit());
        
        InventoryStoreTotalExample.Criteria criteria = example.createCriteria();
        
        if (!StringUtils.isEmpty(request.getGoodsBarCode())) {
            criteria.andGoodsBarCodeLike("%" + request.getGoodsBarCode() + "%");
        }
        if (!StringUtils.isEmpty(request.getGoodsName())) {
            criteria.andGoodsNameLike("%" + request.getGoodsName() + "%");
        }
        if (null != request.getGoodsCategory()) {
            criteria.andGoodsCategoryIdEqualTo(request.getGoodsCategory());
        }
        if (request.getSupplierId() != null) criteria.andSupplierIdEqualTo(request.getSupplierId());
        if (!StringUtils.isEmpty(request.getOperator())) {
            criteria.andOperatorEqualTo(request.getOperator());
        }
        if (!StringUtils.isEmpty(request.getStartDate()) && !StringUtils.isEmpty(request.getEndDate())) {
            criteria.andUpdatedTimeBetween(DateUtils.parse(request.getStartDate(), DateUtils.FORMAT_SHORT), DateUtils.parse(request.getEndDate(), DateUtils.FORMAT_SHORT));
        }
        
        InventoryStoreResponse response = new InventoryStoreResponse();
        response.setTotal(storeMapper.countTotalByExample(example));
        
        response.setData(new ArrayList<>());
        for (InventoryStoreTotal storeTotal : storeMapper.selectTotalByExample(example)) {
            InventoryStoreResponse.Entry entry = new InventoryStoreResponse.Entry();
            entry.setGoodsId(storeTotal.getGoodsId());
            entry.setGoodsBarCode(storeTotal.getGoodsBarCode());
            entry.setGoodsName(storeTotal.getGoodsName());
            entry.setGoodsCategory(storeTotal.getGoodsCategory());
            entry.setSupplier(storeTotal.getSupplierName());
            entry.setGoodsUnit(storeTotal.getGoodsUnit());
            entry.setQualityDate(storeTotal.getQualityDate());
            entry.setStorageNum(storeTotal.getStorageNum());
            entry.setAverageInPrice(storeTotal.getAverageInPrice().setScale(2, BigDecimal.ROUND_UP));
            entry.setTotalInventoryAmount(storeTotal.getTotalInventoryAmount());
            entry.setUpdatedTime(storeTotal.getUpdatedTime());
            entry.setOperator(storeTotal.getOperator());
            entry.setIsStock(storeTotal.getIsStock());
            
            response.getData().add(entry);
        }
        
        return response;
    }
    
    public InventoryTotalAmountResponse getTotalAmount(Integer shopId) {
        if (shopId == null) {
            throw new BusinessCommonException(GoodsErrorCode.MISSING_STORE_ID);
        }
        InventoryTotalAmount totalAmount = storeMapper.selectInventoryTotalAmount(shopId);
        InventoryTotalAmountResponse response = new InventoryTotalAmountResponse();
        
        response.setTotalAmount((totalAmount == null) ? new BigDecimal(0) : totalAmount.getTotalAmount());
        response.setTotalStorageNum((totalAmount == null) ? new BigDecimal(0) : totalAmount.getTotalStorageNum());
        
        return response;
    }
    
    public void exportTotal(Integer shopId, OutputStream os) throws Exception {
        List<String> fieldNames = Arrays.asList("商品条码", "商品名称", "类别", "供应商", "规格", "过期日期", "数量", "进价均价", "库存总金额", "更新时间", "操作人");
        
        InventoryStoreTotalExample example = new InventoryStoreTotalExample();
        example.setShopId(shopId);
        example.setOrderByClause("id desc");
        
        List<List<Object>> fieldData = storeMapper.selectTotalByExample(example).stream().map(storeTotal -> {
            List<Object> objectList = new ArrayList<>();
            objectList.addAll(Arrays.asList(storeTotal.getGoodsBarCode(), storeTotal.getGoodsName(), storeTotal.getGoodsCategory(), storeTotal.getSupplier(), storeTotal.getGoodsUnit(), storeTotal.getQualityDate(), storeTotal.getStorageNum(), storeTotal.getAverageInPrice(), storeTotal.getTotalInventoryAmount(), storeTotal.getUpdatedTime(), storeTotal.getOperator()));
            return objectList;
        }).collect(Collectors.toList());
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ExcelUtils.exportExcel(fieldNames, fieldData, outputStream);
        os.write(outputStream.toByteArray());
        os.flush();
        os.close();
    }
    
    public InventoryStoreHistoryResponse getHistory(InventoryStoreHistoryRequest request) {
        InventoryStoreHistoryExample example = new InventoryStoreHistoryExample();
        
        example.setOrderByClause("isi.id desc");
        
        if (request.getIsPage() == null || request.getIsPage())
            example.page(request.getOffset(), request.getLimit());
        
        InventoryStoreHistoryExample.Criteria criteria = example.createCriteria();
        criteria.andShopIdEqualTo(request.getShopId());
        if (request.getActionDire() != null) {
            criteria.andActionDireEqualTo(request.getActionDire());
        }
        if (!StringUtils.isEmpty(request.getGoodsBarCode())) {
            criteria.andGoodsBarCodeLike("%" + request.getGoodsBarCode() + "%");
        }
        if (!StringUtils.isEmpty(request.getGoodsName())) {
            criteria.andGoodsNameLike("%" + request.getGoodsName() + "%");
        }
        if (!StringUtils.isEmpty(request.getGoodsCategory())) {
            criteria.andGoodsCategoryEqualTo(request.getGoodsCategory());
        }
        if (!StringUtils.isEmpty(request.getStartDate()) && !StringUtils.isEmpty(request.getEndDate())) {
            Calendar c = Calendar.getInstance();
            c.setTime(DateUtils.parse(request.getEndDate(), DateUtils.FORMAT_SHORT));
            c.add(Calendar.DAY_OF_MONTH, 1);
            criteria.andCreatedTimeBetween(DateUtils.parse(request.getStartDate(), DateUtils.FORMAT_SHORT), c.getTime());
        }
        
        InventoryStoreHistoryResponse response = new InventoryStoreHistoryResponse();
        response.setTotal(storeMapper.countHistoryByExample(example));
        response.setData(storeMapper.selectHistoryByExample(example).stream().map(storeHistory -> {
            InventoryStoreHistoryResponse.Entry entry = new InventoryStoreHistoryResponse.Entry();
            entry.setId(storeHistory.getId());
            entry.setCreatedTime(storeHistory.getCreatedTime());
            entry.setGoodsBarCode(storeHistory.getGoodsBarCode());
            entry.setGoodsName(storeHistory.getGoodsName());
            entry.setGoodsCategory(storeHistory.getGoodsCategory());
            entry.setActionType(storeHistory.getActionType());
            entry.setResidueNum(storeHistory.getResidueNum());
            entry.setVarNum(storeHistory.getVarNum());
            entry.setSalePrice(storeHistory.getSalePrice());
            entry.setInPrice(storeHistory.getInPrice());
            try {
                entry.setNewInventoryAmount(storeHistory.getVarNum().multiply(storeHistory.getInPrice()).multiply(new BigDecimal(storeHistory.getActionDire())));
            } catch (NullPointerException e) {
                entry.setNewInventoryAmount(new BigDecimal(0));
            }
            entry.setNewStorageNum(storeHistory.getResidueNum().add(storeHistory.getVarNum().multiply(new BigDecimal(storeHistory.getActionDire()))));
            return entry;
        }).collect(Collectors.toList()));
        
        return response;
    }
    
    public void exportHistory(Integer shopId, OutputStream os) throws Exception {
        List<String> fieldNames = Arrays.asList("更新时间", "商品条码", "商品名称", "类别", "入/出库类别", "上期剩余库存", "本期新增库存", "新增库存单价", "新增库存金额", "总库存");
        
        InventoryStoreHistoryExample example = new InventoryStoreHistoryExample();
        example.setOrderByClause("isi.id desc");
        example.createCriteria().andShopIdEqualTo(shopId);
        
        List<List<Object>> fieldData = storeMapper.selectHistoryByExample(example).stream().map(storeHistory -> {
            List<Object> objectList = new ArrayList<>();
            BigDecimal newAmount;
            try {
                newAmount = storeHistory.getVarNum().multiply(storeHistory.getSalePrice());
            } catch (NullPointerException e) {
                newAmount = new BigDecimal(0);
            }
            
            objectList.addAll(Arrays.asList(storeHistory.getCreatedTime(), storeHistory.getGoodsBarCode(), storeHistory.getGoodsName(), storeHistory.getGoodsCategory(), convertActionTypeName(storeHistory.getActionType()), storeHistory.getResidueNum(), storeHistory.getVarNum(), storeHistory.getSalePrice(), newAmount, storeHistory.getResidueNum().add(storeHistory.getVarNum())));
            return objectList;
        }).collect(Collectors.toList());
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ExcelUtils.exportExcel(fieldNames, fieldData, outputStream);
        os.write(outputStream.toByteArray());
        os.flush();
        os.close();
    }
    
    /**
     * 添加进销存系统配置
     *
     * @param InventoryConfigRequest
     */
    public void createInventoryConfig(InventoryConfigRequest InventoryConfigRequest) {
        inventoryGoodsConfigMapper.insertSelective(BeanUtil.parse(InventoryConfigRequest, InventoryGoodsConfig.class));
    }
    
    /**
     * 修改进销存系统配置
     *
     * @param InventoryConfigRequest
     */
    public void updateInventoryConfig(InventoryConfigRequest InventoryConfigRequest) {
        inventoryGoodsConfigMapper.updateByPrimaryKeySelective(BeanUtil.parse(InventoryConfigRequest, InventoryGoodsConfig.class));
    }
    
    /**
     * 获得进销存系统配置
     *
     * @param orgId
     * @param shopId
     * @return
     */
    public InventoryGoodsConfigResponse getInventoryConfig(Integer orgId, Integer shopId) {
        InventoryGoodsConfigExample example = new InventoryGoodsConfigExample();
        example.createCriteria().andOrgIdEqualTo(orgId).andShopIdEqualTo(shopId);
        return inventoryGoodsConfigMapper.selectByExample(example).stream().findAny().map(item -> {
            InventoryGoodsConfigResponse inventoryGoodsConfigResponse = new InventoryGoodsConfigResponse();
            BeanUtils.copyProperties(item, inventoryGoodsConfigResponse);
            return inventoryGoodsConfigResponse;
        }).orElse(null);
    }
    
    private String convertActionTypeName(String actionType) {
        switch (Integer.parseInt(actionType)) {
            case 10:
                return "进货";
            case 11:
                return "用户退货";
            case 12:
                return "盘盈";
            case 20:
                return "销售";
            case 21:
                return "向供应货退货";
            case 22:
                return "盘损";
            case 23:
                return "领用";
        }
        
        return null;
    }
    
}
