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

import com.alibaba.fastjson.JSON;
import com.neusoft.smart.pos.dto.inventory.request.*;
import com.neusoft.smart.pos.dto.inventory.response.*;
import com.neusoft.smart.pos.framework.bean.PaginationExtendBean;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.BeanUtil;
import com.neusoft.smart.pos.inventory.constants.CateringMenuConstant;
import com.neusoft.smart.pos.inventory.constants.GoodsErrorCode;
import com.neusoft.smart.pos.inventory.constants.InventoryConstant;
import com.neusoft.smart.pos.inventory.persistent.domain.*;
import com.neusoft.smart.pos.inventory.persistent.mapper.InventoryGoodsApprovalOpinionMapper;
import com.neusoft.smart.pos.inventory.persistent.mapper.InventoryGoodsInfoMapper;
import com.neusoft.smart.pos.inventory.util.EmojiUtil;
import com.neusoft.smart.pos.redis.bean.DeviceInfo;
import com.neusoft.smart.pos.utils.PosDeviceRedisUtils;
import com.neusoft.smart.pos.utils.RequestHeaderUtil;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

@EnableTransactionManagement
@Service
public class CateringMenuService {
    
    @Resource
    private InventoryGoodsInfoMapper menuMapper;
    
    @Resource
    private InventoryGoodsApprovalOpinionMapper goodsApprovalOpinionMapper;
    
    @Autowired
    private GoodsDefaultService goodsDefaultService;
    
    
    public MenuListResponse selectMenus(InventoryGoodsQueryRequest request) {
        Integer orgId = RequestHeaderUtil.getOrgId();
        List<Integer> storeIds = RequestHeaderUtil.getStoreIds();
        
        if ("admin".equals(RequestHeaderUtil.getRole())) {
            if (request.getShopId() == null) {
                request.setShopId(0);
            } else if (storeIds != null && !storeIds.contains(request.getShopId())) {
                MenuListResponse result = new MenuListResponse();
                result.setTotal(0);
                result.setData(new ArrayList<>());
                return result;
            }
            
            storeIds = null;
        } else if (request.getShopId() != null && !storeIds.contains(request.getShopId())) {
            MenuListResponse result = new MenuListResponse();
            result.setTotal(0);
            result.setData(new ArrayList<>());
            return result;
        }
        
        return doSelectMenus(request, orgId, storeIds);
    }
    
    public List<PosMenuResponse> selectMenusBySnCode(String snCode) {
        DeviceInfo deviceInfo = PosDeviceRedisUtils.getDeviceInfoBySerialNo(snCode);
        if (null == deviceInfo) {
            throw new BusinessCommonException(GoodsErrorCode.DEVICE_ORG_EMPTY);
        }
        Integer shopId = deviceInfo.getStoreId();
        Integer orgId = deviceInfo.getOrganizationId();
        InventoryGoodsQueryRequest inventoryGoodsQueryRequest = new InventoryGoodsQueryRequest();
        inventoryGoodsQueryRequest.setWithoutServiceCharge(false);
        inventoryGoodsQueryRequest.setOrderByClause("`priority` desc, id desc");
        List<InventoryGoodsResponse> responseList = this.doSelectMenus(inventoryGoodsQueryRequest, orgId, Collections.singletonList(shopId), false).getData();
        List<PosMenuResponse> posMenuResponses = new ArrayList<>();
        responseList.forEach(item -> {
            PosMenuResponse posMenuResponse = new PosMenuResponse();
            posMenuResponse.setId(item.getId());
            posMenuResponse.setName(item.getName());
            posMenuResponse.setPrice(item.getPrice());
            posMenuResponse.setCategory(item.getCateId());
            posMenuResponse.setCateName(item.getCateName());
            posMenuResponse.setTags(String.join("|", item.getTags().values()));
            posMenuResponses.add(posMenuResponse);
        });
        return posMenuResponses;
    }

//    @Transactional
//    public List<Integer> selectMenuIdsByPos(String snCode) {
//        if (StringUtils.isEmpty(snCode)) {
//            throw new BusinessCommonException(GoodsErrorCode.EMPTY_SN_CODE);
//        }
//
//        DeviceInfo deviceInfo = PosDeviceRedisUtils.getDeviceInfoBySerialNo(snCode);
//        if (null == deviceInfo) {
//            throw new BusinessCommonException(GoodsErrorCode.DEVICE_ORG_EMPTY);
//        }
//
//        GoodsCateringMenuPosExample posExample = new GoodsCateringMenuPosExample();
//        posExample.createCriteria().andSerialNoEqualTo(snCode).andShopIdEqualTo(deviceInfo.getStoreId());
//        List<Integer> menuIds = cateringMenuPosMapper.selectByExample(posExample).stream().map(menuPos ->
//                menuPos.getMenuId()
//        ).collect(Collectors.toList());
//
//        return menuIds;
//		/*
//		DeviceInfo deviceInfo = PosDeviceRedisUtils.getDeviceInfoBySerialNo(snCode);
//
//		if (null == deviceInfo) {
//			throw new BusinessCommonException(GoodsErrorCode.DEVICE_ORG_EMPTY);
//		}
//
//		Integer orgId = deviceInfo.getOrganizationId();
//		Integer shopId = deviceInfo.getStoreId();
//
//		GoodsCateringMenuExample example = new GoodsCateringMenuExample();
//		example.createCriteria().andOrgIdEqualTo(orgId).andShopIdEqualTo(shopId);
//
//		menuIds = menuMapper.selectByExample(example).stream().map(menu -> menu.getId()).collect(Collectors.toList());
//		return menuIds;*/
//    }

//    @Transactional
//    public void associateMenus(final String snCode, List<Integer> menuIds) {
//        if (StringUtils.isEmpty(snCode)) {
//            throw new BusinessCommonException(GoodsErrorCode.EMPTY_SN_CODE);
//        }
//
//        DeviceInfo deviceInfo = PosDeviceRedisUtils.getDeviceInfoBySerialNo(snCode);
//        if (null == deviceInfo) {
//            throw new BusinessCommonException(GoodsErrorCode.DEVICE_ORG_EMPTY);
//        }
//
//        Integer shopId = deviceInfo.getStoreId();
//
//        GoodsCateringMenuPosExample example = new GoodsCateringMenuPosExample();
//        example.createCriteria().andSerialNoEqualTo(snCode).andShopIdEqualTo(shopId);
//
//        cateringMenuPosMapper.deleteByExample(example);
//
//        if (menuIds.size() == 0) {
//            return;
//        }
//
//        cateringMenuPosMapper.batchInsert(menuIds.stream().map(menuId -> {
//            GoodsCateringMenuPos entry = new GoodsCateringMenuPos();
//            entry.setSerialNo(snCode);
//            entry.setShopId(shopId);
//            entry.setMenuId(menuId);
//            return entry;
//        }).collect(Collectors.toList()));
//    }
    
    @Transactional
    public List<PosCategoryMenuResponse> selectCategoryMenusBySnCode(String snCode) {
        DeviceInfo deviceInfo = PosDeviceRedisUtils.getDeviceInfoBySerialNo(snCode);
        if (null == deviceInfo) {
            throw new BusinessCommonException(GoodsErrorCode.DEVICE_ORG_EMPTY);
        }
        Integer shopId = deviceInfo.getStoreId();
        Integer orgId = deviceInfo.getOrganizationId();
        
        
        InventoryGoodsQueryRequest inventoryGoodsQueryRequest = new InventoryGoodsQueryRequest();
        inventoryGoodsQueryRequest.setOrderByClause("`priority` desc, id desc");
        inventoryGoodsQueryRequest.setWithoutServiceCharge(false);
        inventoryGoodsQueryRequest.setOrgId(orgId);
        inventoryGoodsQueryRequest.setShopId(shopId);
        inventoryGoodsQueryRequest.setIsPage(false);
        PaginationExtendBean<InventoryGoodsResponse> paginationExtendBean = goodsDefaultService.getPage(inventoryGoodsQueryRequest);
        
        Map<String, List<InventoryGoodsResponse>> categoryMenuMap = new HashMap<>();
        for (InventoryGoodsResponse menu : paginationExtendBean.getRows()) {
            if (!categoryMenuMap.containsKey(menu.getCateId() + "_" + menu.getCateName() + "_" + menu.getPriority())) {
                categoryMenuMap.put(menu.getCateId() + "_" + menu.getCateName()+"_" + menu.getPriority(), new ArrayList<>());
            }
            categoryMenuMap.get(menu.getCateId() + "_" + menu.getCateName() + "_" + menu.getPriority()).add(menu);
        }
        
        List<PosCategoryMenuResponse> result = new ArrayList<>();
        
        categoryMenuMap.forEach((key, value) -> {
            PosCategoryMenuResponse posCategoryMenuResponse = new PosCategoryMenuResponse();
            posCategoryMenuResponse.setId(Integer.valueOf(key.split("_")[0]));
            posCategoryMenuResponse.setCategory(key.split("_")[1]);
            posCategoryMenuResponse.setSortNo(Integer.valueOf(key.split("_")[2]));
            posCategoryMenuResponse.setMenuList(value);
            result.add(posCategoryMenuResponse);
        });
        result.sort((PosCategoryMenuResponse data1, PosCategoryMenuResponse data2) -> {
            return data2.getSortNo().compareTo(data1.getSortNo());
        });
        return result;
    }
    
    private MenuListResponse doSelectMenus(InventoryGoodsQueryRequest request, Integer orgId, List<Integer> storeIds) {
        return doSelectMenus(request, orgId, storeIds, false);
    }
    
    private MenuListResponse doSelectMenus(InventoryGoodsQueryRequest request, Integer orgId, List<Integer> storeIds, Boolean flag) {
        MenuListResponse result = new MenuListResponse();
        
        request.setOrderByClause("`priority` desc, id desc");
        request.setWithoutServiceCharge(flag);
        request.setOrgId(orgId);
        request.setShopIds(storeIds);
        PaginationExtendBean<InventoryGoodsResponse> paginationExtendBean = goodsDefaultService.getPage(request);
        
        result.setData(paginationExtendBean.getRows());
        result.setTotal(paginationExtendBean.getTotal());
        return result;
    }
    
    public FullMenuResponse selectMenuById(Integer id) {
        InventoryGoodsResponse inventoryGoodsResponse = goodsDefaultService.getGoods(id);
        return new FullMenuResponse(inventoryGoodsResponse, inventoryGoodsResponse.getTags());
    }
    
    @Transactional
    public void beforeInsertMenu(CreateMenuRequest request) {
        InventoryGoodsApprovalOpinion goodsApprovalOpinion = new InventoryGoodsApprovalOpinion();
        goodsApprovalOpinion.setApprovalType(0);
        goodsApprovalOpinion.setRequestData(JSON.toJSONString(request));
        goodsApprovalOpinion.setOrgId(RequestHeaderUtil.getOrgId());
        goodsApprovalOpinion.setCreatedBy(RequestHeaderUtil.getUserId());
        goodsApprovalOpinion.setStoreId(request.getShop());
        goodsApprovalOpinionMapper.insertSelective(goodsApprovalOpinion);
    }
    
    @Transactional
    public SimpleMenuResponse insertMenu(CreateMenuRequest request) {
        if (request.getName().length() > CateringMenuConstant.MAX_NAME_LENGTH) {
            throw new BusinessCommonException(GoodsErrorCode.TOO_LONG_CATERING_MENU_NAME);
        }
        
        if (EmojiUtil.containsEmoji(request.getName())) {
            throw new BusinessCommonException(GoodsErrorCode.INVALID_GOODS_NAME);
        }
        
        Integer orgId = RequestHeaderUtil.getOrgId();
        Integer storeId;
        List<Integer> storeIds = RequestHeaderUtil.getStoreIds();
        if ("admin".equals(RequestHeaderUtil.getRole())) {
            if (request.getShop() == null) {
                storeId = 0;
            } else if (storeIds.contains(request.getShop())) {
                storeId = request.getShop();
            } else {
                throw new BusinessCommonException(GoodsErrorCode.INVALID_SHOP);
            }
        } else if (request.getShop() != null && request.getShop() != 0 && storeIds.contains(request.getShop())) {
            storeId = request.getShop();
        } else {
            throw new BusinessCommonException(GoodsErrorCode.INVALID_SHOP);
        }
        PostInventoryGoodsInfoRequest postInventoryGoodsInfoRequest = new PostInventoryGoodsInfoRequest();
        BeanUtils.copyProperties(request, postInventoryGoodsInfoRequest);
        postInventoryGoodsInfoRequest.setOrg(orgId);
        postInventoryGoodsInfoRequest.setStore(storeId);
        postInventoryGoodsInfoRequest.setIsStock(InventoryConstant.NO);
        postInventoryGoodsInfoRequest.setPrice(new BigDecimal(request.getPrice()));
        postInventoryGoodsInfoRequest.setCategoryId(request.getCategory());
        goodsDefaultService.createGoods(postInventoryGoodsInfoRequest);
        return new SimpleMenuResponse();
    }
    
    @Transactional
    public void beforeUpdateMenu(PatchUpdateMenuRequest request) {
        InventoryGoodsApprovalOpinion goodsApprovalOpinion = new InventoryGoodsApprovalOpinion();
        goodsApprovalOpinion.setApprovalType(1);
        goodsApprovalOpinion.setGoodsId(request.getId());
        goodsApprovalOpinion.setRequestData(JSON.toJSONString(request));
        goodsApprovalOpinion.setOriginalData(JSON.toJSONString(menuMapper.selectByPrimaryKey(request.getId())));
        goodsApprovalOpinion.setOrgId(RequestHeaderUtil.getOrgId());
        goodsApprovalOpinion.setStoreId(request.getShop());
        goodsApprovalOpinion.setCreatedBy(RequestHeaderUtil.getUserId());
        goodsApprovalOpinionMapper.insertSelective(goodsApprovalOpinion);
    }
    
    @Transactional
    public SimpleMenuResponse updateMenu(PatchUpdateMenuRequest request) {
        List<Integer> storeIds = RequestHeaderUtil.getStoreIds();
        if (request.getShop() != null && request.getShop() != 0) {
            if (storeIds == null || !storeIds.contains(request.getShop())) {
                throw new BusinessCommonException(GoodsErrorCode.INVALID_SHOP);
            }
        }
        PutInventoryGoodsInfoRequest putInventoryGoodsInfoRequest = new PutInventoryGoodsInfoRequest();
        BeanUtils.copyProperties(request, putInventoryGoodsInfoRequest);
        putInventoryGoodsInfoRequest.setPrice(new BigDecimal(request.getPrice()));
        putInventoryGoodsInfoRequest.setCategoryId(request.getCategory());
        putInventoryGoodsInfoRequest.setOrg(RequestHeaderUtil.getOrgId());
        putInventoryGoodsInfoRequest.setStore(request.getShop());
        goodsDefaultService.updateGoods(putInventoryGoodsInfoRequest);
//TODO 以后可能会处理菜单和标签的关系

//        List<Integer> tags = request.getTags();
//        if (tags != null) {
//            deleteGoodsMenuTag(menuId);
//            if (tags.size() > 0) insertGoodsMenuTag(menuId, tags);
//        } else {
//            tags = new ArrayList<>();
//            GoodsCateringMenuTagExample menuTagExample = new GoodsCateringMenuTagExample();
//            GoodsCateringMenuTagExample.Criteria menuTagExampleCriteria = menuTagExample.createCriteria();
//            menuTagExampleCriteria.andMenuIdEqualTo(menuId);
//
//            for (GoodsCateringMenuTag menuTag : inventoryGoodsTagRefMapper.selectByExample(menuTagExample)) {
//                tags.add(menuTag.getTagId());
//            }
//        }
        return new SimpleMenuResponse();
    }
    
    @Transactional
    public void deleteMenu(Integer id) {
        goodsDefaultService.deleteGoods(id, true);
    }
    
    
    private void insertGoodsMenuTag(Integer menuId, List<Integer> tags) {
//        if (tags != null && tags.size() > 0) {
//            List<GoodsCateringMenuTag> menuTags = new ArrayList<>();
//            for (Integer tagId : tags) {
//                GoodsCateringMenuTag menuTag = new GoodsCateringMenuTag();
//                menuTag.setMenuId(menuId);
//                menuTag.setTagId(tagId);
//                menuTags.add(menuTag);
//            }
//            inventoryGoodsTagRefMapper.batchInsert(menuTags);
//        }
    }
    
    private void deleteGoodsMenuTag(Integer menuId) {
//        GoodsCateringMenuTagExample example = new GoodsCateringMenuTagExample();
//        GoodsCateringMenuTagExample.Criteria criteria = example.createCriteria();
//        criteria.andMenuIdEqualTo(menuId);
//
//        inventoryGoodsTagRefMapper.deleteByExample(example);
    }
    
    public MenuListResponse selectMenuByShopId(Integer shopId) {
        InventoryGoodsQueryRequest inventoryGoodsQueryRequest = new InventoryGoodsQueryRequest();
        inventoryGoodsQueryRequest.setShopId(shopId);
        inventoryGoodsQueryRequest.setIsPage(false);
        inventoryGoodsQueryRequest.setOnSale(1);
        val result = goodsDefaultService.getPage(inventoryGoodsQueryRequest);
        MenuListResponse menuListResponse = new MenuListResponse();
        menuListResponse.setTotal(result.getTotal());
        menuListResponse.setData(result.getRows());
        return menuListResponse;
    }
    
    /**
     * 审批
     *
     * @param goodsApprovalRequest
     */
    public void approvalMenu(GoodsApprovalRequest goodsApprovalRequest) {
        if (goodsApprovalRequest.getApprovalStatus() == 2 && goodsApprovalRequest.getIds().size() > 1) {
            throw new BusinessCommonException(GoodsErrorCode.GOODS_DUPLICATE_IDS);
        }
        goodsApprovalRequest.getIds().sort(Comparator.comparingInt(x -> x));
        for (Integer id : goodsApprovalRequest.getIds()) {
            InventoryGoodsApprovalOpinion goodsApprovalOpinion = goodsApprovalOpinionMapper.selectByPrimaryKey(id);
            if (goodsApprovalOpinion.getApprovalStatus() != 0) {
                continue;
            }
            goodsApprovalOpinion.setApprovalStatus(goodsApprovalRequest.getApprovalStatus());
            goodsApprovalOpinion.setId(id);
            goodsApprovalOpinion.setOpinion(goodsApprovalRequest.getOpinion());
            
            if (goodsApprovalOpinion.getApprovalType().equals(0) && goodsApprovalOpinion.getApprovalStatus().equals(1)) {
                CreateMenuRequest createMenuRequest = JSON.parseObject(goodsApprovalOpinion.getRequestData(), CreateMenuRequest.class);
                SimpleMenuResponse simpleMenuResponse = this.insertMenu(createMenuRequest);
                goodsApprovalOpinion.setGoodsId(simpleMenuResponse.getId());
            } else if (goodsApprovalOpinion.getApprovalType().equals(1) && goodsApprovalOpinion.getApprovalStatus().equals(1)) {
                PatchUpdateMenuRequest patchUpdateMenuRequest = JSON.parseObject(goodsApprovalOpinion.getRequestData(), PatchUpdateMenuRequest.class);
                this.updateMenu(patchUpdateMenuRequest);
            }
            goodsApprovalOpinionMapper.updateByPrimaryKeySelective(goodsApprovalOpinion);
        }
        
    }
    
    public List<GoodsApprovalOpinionResponse> getList(GoodsApprovalQueryRequest goodsApprovalQueryRequest) {
        InventoryGoodsApprovalOpinionExample goodsApprovalOpinionExample = this.exampleProvider(goodsApprovalQueryRequest);
        if (goodsApprovalQueryRequest.getIsPage()) {
            goodsApprovalOpinionExample.setLimit(goodsApprovalQueryRequest.getLimit());
            goodsApprovalOpinionExample.setOffset(goodsApprovalQueryRequest.getOffset());
        }
        return BeanUtil.parseList(goodsApprovalOpinionMapper.selectByExample(goodsApprovalOpinionExample), GoodsApprovalOpinionResponse.class);
    }
    
    /**
     * @return
     */
    public Integer getCount(GoodsApprovalQueryRequest goodsApprovalQueryRequest) {
        InventoryGoodsApprovalOpinionExample goodsApprovalOpinionExample = this.exampleProvider(goodsApprovalQueryRequest);
        return goodsApprovalOpinionMapper.countByExample(goodsApprovalOpinionExample);
    }
    
    private InventoryGoodsApprovalOpinionExample exampleProvider(GoodsApprovalQueryRequest goodsApprovalQueryRequest) {
        InventoryGoodsApprovalOpinionExample goodsApprovalOpinionExample = new InventoryGoodsApprovalOpinionExample();
        goodsApprovalOpinionExample.setOrderByClause("created_time desc, approval_status");
        InventoryGoodsApprovalOpinionExample.Criteria criteria = goodsApprovalOpinionExample.createCriteria();
        if (null != goodsApprovalQueryRequest.getStoreId()) {
            criteria.andStoreIdEqualTo(goodsApprovalQueryRequest.getStoreId());
        }
        switch (RequestHeaderUtil.getRole()) {
            case "admin":
                criteria.andOrgIdEqualTo(RequestHeaderUtil.getOrgId());
                break;
            case "user":
                criteria.andCreatedByEqualTo(RequestHeaderUtil.getUserId());
                break;
            default:
        }
        
        return goodsApprovalOpinionExample;
    }
    
    @Transactional
    public void reorder(Map<Integer, Integer> orderMap) {
        InventoryGoodsInfoExample example = new InventoryGoodsInfoExample();
        example.createCriteria().andIdIn(new ArrayList<>(orderMap.keySet()));
        for (InventoryGoodsInfo menu : menuMapper.selectByExample(example)) {
            if (!menu.getPriority().equals(orderMap.get(menu.getId()))) {
                menu.setUpdatedTime(new Date());
                menu.setPriority(orderMap.get(menu.getId()));
                menuMapper.updateByPrimaryKey(menu);
            }
        }
    }
    
    /**
     * 查询门店配置是否需要审批
     *
     * @param orgId
     * @param shopId
     * @return
     */
    public Boolean needApproval(Integer orgId, Integer shopId) {
        InventoryGoodsConfig inventoryGoodsConfig = goodsDefaultService.getConfig(orgId, shopId);
        if (null == inventoryGoodsConfig) {
            return false;
        } else {
            return InventoryConstant.YES.equals(inventoryGoodsConfig.getNeedApproval());
        }
    }
}
