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

import com.neusoft.smart.pos.framework.bean.PaginationExtendBean;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.ExcelUtils;
import com.neusoft.smart.pos.inventory.constants.GoodsConstant;
import com.neusoft.smart.pos.inventory.constants.GoodsErrorCode;
import com.neusoft.smart.pos.inventory.constants.InventoryConstant;
import com.neusoft.smart.pos.dto.inventory.request.BatchCreateRetailGoodsRequest;
import com.neusoft.smart.pos.dto.inventory.request.GetCategoriesRequest;
import com.neusoft.smart.pos.dto.inventory.request.GetRetailGoodsListRequest;
import com.neusoft.smart.pos.dto.inventory.request.InventoryGoodsQueryRequest;
import com.neusoft.smart.pos.dto.inventory.request.PostInventoryGoodsInfoRequest;
import com.neusoft.smart.pos.dto.inventory.request.PutInventoryGoodsInfoRequest;
import com.neusoft.smart.pos.dto.inventory.response.GoodsListResponse;
import com.neusoft.smart.pos.dto.inventory.response.InventoryCategoryTreeResponse;
import com.neusoft.smart.pos.dto.inventory.response.InventoryGoodsResponse;
import com.neusoft.smart.pos.inventory.persistent.domain.InventoryGoodsInfo;
import com.neusoft.smart.pos.inventory.util.EmojiUtil;
import com.neusoft.smart.pos.utils.RequestHeaderUtil;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidationConstraint;
import org.apache.poi.xssf.usermodel.XSSFDataValidationHelper;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

@Service
@EnableTransactionManagement
public class InventoryGoodsInfoService extends BaseGoodsService {
    
    @Autowired
    private GoodsDefaultService goodsDefaultService;
    
    @Autowired
    private InventoryGoodsCategoryService categoryService;
    
    public GoodsListResponse<InventoryGoodsResponse> selectGoodsList(GetRetailGoodsListRequest request) {
        if ("admin".equals(RequestHeaderUtil.getRole())) {
            request.setStore(0);
        } else {
            Integer store = request.getStore();
            if (store != null) {
                validateStore(store);
            } else {
                request.setStoreIds(RequestHeaderUtil.getStoreIds());
            }
        }
        request.setOrg(RequestHeaderUtil.getOrgId());
        PaginationExtendBean<InventoryGoodsResponse> paginationExtendBean = doSelectGoodsList(request);
        GoodsListResponse<InventoryGoodsResponse> result = new GoodsListResponse<>();
        result.setTotal(paginationExtendBean.getTotal());
        //TODO 需要解析类别全名xxx-xxx的形式
        result.setData(paginationExtendBean.getRows());
        return result;
    }
    
    public List<InventoryGoodsResponse> selectGoodsListBySnCode(String snCode) {
        GetRetailGoodsListRequest request = new GetRetailGoodsListRequest();
        setRequestBySnCode(snCode, request);
        //TODO 需要解析类别全名xxx-xxx的形式
        return doSelectGoodsList(request).getRows();
    }
    
    private PaginationExtendBean<InventoryGoodsResponse> doSelectGoodsList(GetRetailGoodsListRequest request) {
        InventoryGoodsQueryRequest inventoryGoodsQueryRequest = new InventoryGoodsQueryRequest();
        BeanUtils.copyProperties(request, inventoryGoodsQueryRequest);
        if (request.getOrg() != null) inventoryGoodsQueryRequest.setOrgId(request.getOrg());
        if (request.getOnSale() != null) inventoryGoodsQueryRequest.setOnSale(request.getOnSale());
        
        if (request.getStoreIds() != null) {
            inventoryGoodsQueryRequest.setShopIds(request.getStoreIds());
        } else if (request.getStore() != null) {
            inventoryGoodsQueryRequest.setShopId(request.getStore());
        }
        
        if (!StringUtils.isEmpty(request.getBarCode())) inventoryGoodsQueryRequest.setBarCode(request.getBarCode());
        if (!StringUtils.isEmpty(request.getName())) inventoryGoodsQueryRequest.setName(request.getName());
        if (null != request.getCategoryId())
            //FIXME 此处需要解析成查询类别的叶子所有叶子节点
            inventoryGoodsQueryRequest.setCategories(request.getCategoryId().toString());
        
        
        return goodsDefaultService.getPage(inventoryGoodsQueryRequest);
    }
    
    public InventoryGoodsResponse selectGoodsById(Integer id) {
        return goodsDefaultService.getGoods(id);
    }
    
    /**
     * 根据一维码查询商品
     *
     * @param orgId
     * @param shopId
     * @param barCode
     * @return
     */
    public InventoryGoodsResponse selectGoodsByBarCode(Integer orgId, Integer shopId, String barCode) {
        InventoryGoodsQueryRequest inventoryGoodsQueryRequest = new InventoryGoodsQueryRequest();
        inventoryGoodsQueryRequest.setOrgId(orgId);
        inventoryGoodsQueryRequest.setShopId(shopId);
        inventoryGoodsQueryRequest.setBarCode(barCode);
        PaginationExtendBean<InventoryGoodsResponse> paginationExtendBean = goodsDefaultService.getPage(inventoryGoodsQueryRequest);
        return paginationExtendBean.getRows().isEmpty() ? null : paginationExtendBean.getRows().get(0);
    }
    
    public void insertGoods(PostInventoryGoodsInfoRequest request) {
        if ("admin".equals(RequestHeaderUtil.getRole())) {
            request.setStore(0);
        } else {
            if (request.getStore() == null) {
                throw new BusinessCommonException(GoodsErrorCode.MISSING_STORE_ID);
            }
            validateStore(request.getStore());
        }
        
        request.setOrg(RequestHeaderUtil.getOrgId());
        
        InventoryGoodsInfo goods = new InventoryGoodsInfo();
        goods.setBarCode(validateBarCode(request.getBarCode()));
        goods.setName(validateName(request.getName()));
        goods.setPrice(request.getPrice());
        goods.setUnit(validateUnit(request.getUnit()));
        goods.setCateId(request.getCategoryId());
        
        goods.setOnSale(request.getOnSale() != null ? request.getOnSale() : 1);
        goods.setOrgId(request.getOrg());
        goods.setShopId(request.getStore());
        
        Date date = new Date();
        goods.setCreatedTime(date);
        goods.setUpdatedTime(date);
        
        goodsDefaultService.createGoods(request);
        
    }
    
    public void updateGoods(PutInventoryGoodsInfoRequest request) {
        Integer store = request.getStore();
        if (!"admin".equals(RequestHeaderUtil.getRole()) && store != null) {
            validateStore(store);
            request.setStore(store);
        }
        goodsDefaultService.updateGoods(request);
    }
    
    public void deleteGoods(Integer id) {
        goodsDefaultService.deleteGoods(id, true);
    }
    
    public Pair<List<InventoryGoodsResponse>, List<InventoryGoodsResponse>> parseGoodsListFromCsv(Integer orgId, Integer shopId, MultipartFile file) {
        List<InventoryGoodsResponse> result = new ArrayList<>();
        List<InventoryGoodsResponse> errorList = new ArrayList<>();
        try {
            List<String[]> data = ExcelUtils.parseFile(file);
            
            HashSet<String> barCodeSet = new HashSet<>();
            data.forEach(items -> {
                if (items.length != 7) {
                    GoodsErrorCode errorCode = GoodsErrorCode.INVALID_IMPORT_LINE;
                    throw new BusinessCommonException(
                            errorCode.getCode(), errorCode.getMessage() + Arrays.toString(items));
                }
                
                InventoryGoodsResponse response = new InventoryGoodsResponse();
                for (int i = 0; i < items.length; i++) {
                    //条形码	商品名称	商品价格	商品类型	规格	规格精度	是否库存管理
                    switch (i) {
                        case 0:
                            String barCode = items[i];
                            
                            response.setBarCode(validateBarCode(barCode));
                            if (barCodeSet.contains(barCode)) {
                                throw new BusinessCommonException(GoodsErrorCode.DUPLICATE_BAR_CODE);
                            }
                            barCodeSet.add(barCode);
                            break;
                        case 1:
                            response.setName(validateName(items[i]));
                            break;
                        case 2:
                            response.setPrice(validatePrice(items[i]));
                            break;
                        case 3:
                            response.setCateName(items[i]);
                            break;
                        case 4:
                            response.setUnit(validateUnit(items[i]));
                            break;
                        case 5:
                            response.setScale(Integer.valueOf(items[i]));
                            break;
                        case 6:
                            response.setIsStockStr(items[i]);
                            break;
                    }
                }
                if (!goodsDefaultService.checkDuplicateGoods(orgId, shopId, response.getBarCode(), response.getName())) {
                    result.add(response);
                } else {
                    errorList.add(response);
                }
            });
        } catch (BusinessCommonException e) {
            throw e;
        } catch (Exception e) {
            throw new BusinessCommonException(GoodsErrorCode.PARSE_IMPORT_FILE_ERROR);
        }
        
        return Pair.of(result, errorList);
    }
    
    @Transactional
    public void batchInsertGoodsList(BatchCreateRetailGoodsRequest request) {
        Integer org = RequestHeaderUtil.getOrgId();
        Integer store;
        
        if ("admin".equals(RequestHeaderUtil.getRole())) {
            store = 0;
        } else {
            if (request.getStore() == null) {
                throw new BusinessCommonException(GoodsErrorCode.MISSING_STORE_ID);
            }
            store = request.getStore();
            validateStore(store);
        }
        
        
        List<BatchCreateRetailGoodsRequest.Item> dataset = request.getData();
        int batch_Insert_Chunk_Size = 50;
        List<PostInventoryGoodsInfoRequest> chuck = new ArrayList<>(batch_Insert_Chunk_Size);
        
        for (BatchCreateRetailGoodsRequest.Item data : dataset) {
            PostInventoryGoodsInfoRequest goods = new PostInventoryGoodsInfoRequest();
            BeanUtils.copyProperties(data, goods);
            goods.setOnSale(InventoryConstant.YES);
            goods.setOrg(org);
            goods.setStore(store);
            
            chuck.add(goods);
            
            if (chuck.size() == batch_Insert_Chunk_Size) {
                goodsDefaultService.batchCreateGoods(chuck);
                chuck.clear();
            }
        }
        
        if (chuck.size() > 0) {
            goodsDefaultService.batchCreateGoods(chuck);
        }
    }
    
    public void downloadTemplate(Integer shopId, OutputStream os) throws IOException {
        XSSFWorkbook workBook = new XSSFWorkbook();//创建一个工作簿
        XSSFSheet sheet = workBook.createSheet("商品数据");//创建工作表
        Row headRow = sheet.createRow(0); //创建第一栏，抬头栏
        
        //设置单元格格式
        CellStyle style = workBook.createCellStyle();
        Font font = workBook.createFont();
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        short color = HSSFColor.RED.index;
        font.setColor(color);
        style.setFont(font);
        //将数据填入单元格
        Cell cell = headRow.createCell(0);//创建抬头栏单元格
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(style);
        cell.setCellValue("条形码");
        cell = headRow.createCell(1);//创建抬头栏单元格
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(style);
        cell.setCellValue("商品名称");
        cell = headRow.createCell(2);//创建抬头栏单元格
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(style);
        cell.setCellValue("商品价格");
        GetCategoriesRequest request = new GetCategoriesRequest();
        request.setShop(shopId);
        request.setOrg(RequestHeaderUtil.getOrgId());
        request.setDeleted(InventoryConstant.NO);
        List<String> categoriesName = convert2StringList(categoryService.getCategoryTree(request));
        
        CellRangeAddressList regions = new CellRangeAddressList(1, 65535, 3, 3);
        XSSFDataValidationHelper validationHelper = new XSSFDataValidationHelper(sheet);
        XSSFDataValidationConstraint constraint = (XSSFDataValidationConstraint) validationHelper.createExplicitListConstraint(categoriesName.toArray(new String[0])); //将list中的内容写入到excel中
        sheet.addValidationData(validationHelper.createValidation(constraint, regions)); //对sheet生效
        cell = headRow.createCell(3);//创建抬头栏单元格
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(style);
        cell.setCellValue("商品类型");
        cell = headRow.createCell(4);//创建抬头栏单元格
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(style);
        cell.setCellValue("规格");
        cell = headRow.createCell(5);//创建抬头栏单元格
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(style);
        cell.setCellValue("规格精度");
        regions = new CellRangeAddressList(1, 65535, 6, 6);
        constraint = (XSSFDataValidationConstraint) validationHelper.createExplicitListConstraint(new String[]{"0_否", "1_是"}); //将list中的内容写入到excel中
        sheet.addValidationData(validationHelper.createValidation(constraint, regions)); //对sheet生效
        cell = headRow.createCell(6);//创建抬头栏单元格
        cell.setCellType(HSSFCell.CELL_TYPE_STRING);
        cell.setCellStyle(style);
        cell.setCellValue("是否库存管理");
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        workBook.write(outputStream);
        os.write(outputStream.toByteArray());
        os.flush();
        os.close();
    }
    
    private String validateBarCode(String barCode) {
        if (barCode.length() > GoodsConstant.BAR_CODE_SIZE) {
            throw new BusinessCommonException(
                    GoodsErrorCode.INVALID_BAR_CODE.getCode(), GoodsErrorCode.INVALID_BAR_CODE.getMessage() + ": " + barCode);
        }
        return barCode;
    }
    
    private String validateName(String name) {
        if (name.length() > GoodsConstant.MAX_GOODS_NAME_LENGTH || EmojiUtil.containsEmoji(name)) {
            throw new BusinessCommonException(
                    GoodsErrorCode.INVALID_GOODS_NAME.getCode(), GoodsErrorCode.INVALID_GOODS_NAME.getMessage() + ": " + name);
        }
        return name;
    }
    
    private String validateUnit(String unit) {
        if (unit.length() > GoodsConstant.MAX_GOODS_UNIT_LENGTH) {
            throw new BusinessCommonException(
                    GoodsErrorCode.INVALID_UNIT_NAME.getCode(), GoodsErrorCode.INVALID_GOODS_NAME.getMessage() + ": " + unit);
        }
        return unit;
    }
    
    private BigDecimal validatePrice(String priceStr) {
        BigDecimal price;
        try {
            price = new BigDecimal(priceStr);
            if (price.compareTo(new BigDecimal(0)) <= 0) {
                throw new BusinessCommonException(
                        GoodsErrorCode.INVALID_PRICE.getCode(), GoodsErrorCode.INVALID_PRICE.getMessage() + ": " + price);
            }
        } catch (Exception e) {
            GoodsErrorCode errorCode = GoodsErrorCode.INVALID_PRICE;
            throw new BusinessCommonException(errorCode.getCode(), errorCode.getMessage() + ": " + priceStr);
        }
        
        return price;
    }
    
    private List<String> convert2StringList(List<InventoryCategoryTreeResponse> inventoryCategoryTreeResponses) {
        List<String> names = new ArrayList<>();
        inventoryCategoryTreeResponses.forEach(item -> {
            if (item.getChildren().isEmpty()) {
                names.add(item.getId() + "_" + item.getName());
            } else {
                names.addAll(this.convert2StringList(item.getChildren()));
            }
        });
        return names;
    }
}
