package com.yc.ship.module.product.service.voyagestockdistribute;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.collection.CollectionUtils;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.mybatis.core.util.MyBatisUtils;
import com.yc.ship.framework.security.core.util.SecurityFrameworkUtils;
import com.yc.ship.module.ota.api.OtaDistributorApi;
import com.yc.ship.module.ota.api.dto.DistributorRespDTO;
import com.yc.ship.module.ota.enums.DistributorTypeEnum;
import com.yc.ship.module.otc.api.store.StoreApi;
import com.yc.ship.module.otc.api.store.dto.StoreInfoRespDTO;
import com.yc.ship.module.product.controller.admin.voyagestockdistribute.vo.*;
import com.yc.ship.module.product.controller.admin.voyagestockdistribute.vo.QueryCanSelectRoomListReqVO;
import com.yc.ship.module.product.dal.dataobject.voyage.VoyageDO;
import com.yc.ship.module.product.dal.dataobject.voyagestockdetail.VoyageStockDetailDO;
import com.yc.ship.module.product.dal.dataobject.voyagestockdistribute.VoyageStockDistributeDO;
import com.yc.ship.module.product.dal.dataobject.voyagestockdistribute.VoyageStockDistributeLogDO;
import com.yc.ship.module.product.dal.mysql.voyagestockdistribute.VoyageStockDistributeLogMapper;
import com.yc.ship.module.product.dal.mysql.voyagestockdistribute.VoyageStockDistributeMapper;
import com.yc.ship.module.product.enums.ErrorCodeConstants;
import com.yc.ship.module.product.service.voyage.VoyageService;
import com.yc.ship.module.product.service.voyagestockdetail.VoyageStockDetailService;
import com.yc.ship.module.resource.api.room.RoomApi;
import com.yc.ship.module.resource.api.room.dto.RoomRespDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.product.enums.ErrorCodeConstants.USER_NOT_DISTRIBUTOR;

/**
 * 航次库存分配 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class VoyageStockDistributeServiceImpl implements VoyageStockDistributeService {

    @Resource
    private VoyageStockDistributeMapper voyageStockDistributeMapper;

    @Resource
    private VoyageStockDistributeLogMapper voyageStockDistributeLogMapper;

    @Resource
    private VoyageStockDetailService voyageStockDetailService;

    @Resource
    private VoyageService voyageService;

    @Resource
    private OtaDistributorApi otaDistributorApi;

    @Resource
    private StoreApi storeApi;

    @Resource
    private RoomApi roomApi;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createVoyageStockDistribute(List<VoyageStockDistributeSaveReqVO> createReqVO) {
        Long voyageId = createReqVO.get(0).getVoyageId();
        VoyageDO voyage = voyageService.getVoyage(voyageId);
        Long shipId = voyage.getShipId();
        createReqVO.stream().forEach(item -> {
            item.setShipId(shipId);
        });
        // 插入库存设置日志表
        List<VoyageStockDistributeLogDO> logList = BeanUtils.toBean(createReqVO, VoyageStockDistributeLogDO.class);
        voyageStockDistributeLogMapper.insertBatch(logList);

        BigDecimal zero = BigDecimal.ZERO;
        //修改或插入库存表
        List<VoyageStockDistributeDO> list = voyageStockDistributeMapper.selectListByVoyageId(voyageId);
        if(CollectionUtils.isAnyEmpty(list)) {//为空则新增
            list = BeanUtils.toBean(createReqVO, VoyageStockDistributeDO.class);
            list.stream().forEach(item -> {
                item.setBookNum(zero);
                item.setSurplusNum(item.getNum());
                item.setRoomModelNum(item.getRoomModelNum());
            });
            voyageStockDistributeMapper.insertBatch(list);
        }else { //不为空则修改库存
            Map<String, BigDecimal> roomNumMap = CollectionUtils.convertMap(createReqVO, item -> {
                //key为航次ID_分销商类型_分销商ID_门店ID_房型ID_楼层号作为唯一
                return item.getVoyageId() + "_" + item.getDistributorType()
                        + "_" + item.getDistributorId() + "_" + item.getStoreId()
                        + "_" + item.getRoomModelId() + "_" + item.getFloor();
            }, item -> item.getNum());
            Map<String, BigDecimal> roomModelNumMap = CollectionUtils.convertMap(createReqVO, item -> {
                //key为航次ID_分销商类型_分销商ID_门店ID_房型ID_楼层号作为唯一
                return item.getVoyageId() + "_" + item.getDistributorType()
                        + "_" + item.getDistributorId() + "_" + item.getStoreId()
                        + "_" + item.getRoomModelId() + "_" + item.getFloor();
            }, item -> item.getRoomModelNum());

            Map<String, List<Integer>> roomNumsMap = CollectionUtils.convertMap(createReqVO, item -> {
                //key为航次ID_分销商类型_分销商ID_门店ID_房型ID_楼层号作为唯一
                return item.getVoyageId() + "_" + item.getDistributorType()
                        + "_" + item.getDistributorId() + "_" + item.getStoreId()
                        + "_" + item.getRoomModelId() + "_" + item.getFloor();
            }, item -> item.getRoomNums());


            list.stream().forEach(item -> {
                String key = item.getVoyageId() + "_" + item.getDistributorType()
                        + "_" + item.getDistributorId() + "_" + item.getStoreId()
                        + "_" + item.getRoomModelId() + "_" + item.getFloor();
                item.setNum(item.getNum().add(roomNumMap.get(key)));
                item.setSurplusNum(item.getSurplusNum().add(roomNumMap.get(key)));
                item.setRoomModelNum(roomModelNumMap.get(key));
                item.setRoomNums(roomNumsMap.get(key));
            });
            voyageStockDistributeMapper.updateBatch(list);

            //找出多了的分销商或者门店
            List<String> keys = CollectionUtils.convertList(list, item -> {
                return item.getVoyageId() + "_" + item.getDistributorType()
                        + "_" + item.getDistributorId() + "_" + item.getStoreId()
                        + "_" + item.getRoomModelId() + "_" + item.getFloor();
            });
            List<VoyageStockDistributeSaveReqVO> newList = createReqVO.stream().filter(item -> {
                String key = item.getVoyageId() + "_" + item.getDistributorType()
                        + "_" + item.getDistributorId() + "_" + item.getStoreId()
                        + "_" + item.getRoomModelId() + "_" + item.getFloor();
                return !keys.contains(key);
            }).collect(Collectors.toList());
            if(!CollectionUtils.isAnyEmpty(newList)) {
                List<VoyageStockDistributeDO> addList = BeanUtils.toBean(newList, VoyageStockDistributeDO.class);
                addList.stream().forEach(item -> {
                    item.setBookNum(zero);
                    item.setSurplusNum(item.getNum());
                    item.setRoomModelNum(item.getRoomModelNum());
                });
                voyageStockDistributeMapper.insertBatch(addList);
            }
        }

    }

    @Override
    public void updateVoyageStockDistribute(VoyageStockDistributeSaveReqVO updateReqVO) {
        // 更新
        VoyageStockDistributeDO updateObj = BeanUtils.toBean(updateReqVO, VoyageStockDistributeDO.class);
        voyageStockDistributeMapper.updateById(updateObj);
    }

    @Override
    public void deleteVoyageStockDistribute(Long id) {
        // 删除
        voyageStockDistributeMapper.deleteById(id);
    }



    @Override
    public VoyageStockDistributeDO getVoyageStockDistribute(Long id) {
        return voyageStockDistributeMapper.selectById(id);
    }

    @Override
    public PageResult<VoyageStockDistributeRespPageVO> getVoyageStockDistributePage(VoyageStockDistributePageReqVO pageReqVO) {
        Long loginDistributorId = SecurityFrameworkUtils.getLoginDistributorId();
        if(loginDistributorId == null) {
            throw exception(USER_NOT_DISTRIBUTOR);
        }
        pageReqVO.setDistributorId(loginDistributorId);
        Long loginStoreId = SecurityFrameworkUtils.getLoginStoreId();
        pageReqVO.setStoreId(loginStoreId);
        IPage<VoyageStockDistributeRespPageVO> page = MyBatisUtils.buildPage(pageReqVO);
        IPage iPage = voyageStockDistributeMapper.selectPage(page,pageReqVO);
        return new PageResult<>(iPage.getRecords(), iPage.getTotal());
    }

    @Override
    public List<VoyageStockDistributeDO> getListByVoyageId(Long voyageId) {
        List<VoyageStockDistributeDO> list = new ArrayList<>();
        VoyageDO voyage = voyageService.getVoyage(voyageId);
        List<VoyageStockDetailDO> stockDetailList = voyageStockDetailService.getListByVoyageId(voyageId);
        // OTA分销商类型数据
        stockDetailList.stream().forEach(item -> {
            VoyageStockDistributeDO stockDistributeDO = new VoyageStockDistributeDO();
            stockDistributeDO.setVoyageId(item.getVoyageId());
            stockDistributeDO.setRoomModelId(item.getRoomModelId());
            stockDistributeDO.setRoomModelName(item.getRoomModelName());
            stockDistributeDO.setFloor(item.getFloor());
            stockDistributeDO.setNum(BigDecimal.ZERO);
            stockDistributeDO.setDistributorType(DistributorTypeEnum.OTA.getType());
            stockDistributeDO.setDistributorTypeName(DistributorTypeEnum.OTA.getName());
            stockDistributeDO.setDistributorId(null);
            stockDistributeDO.setStoreId(null);
            stockDistributeDO.setShipId(voyage.getShipId());
            list.add(stockDistributeDO);
        });
        //旅行社分销商类型数据
        stockDetailList.stream().forEach(item -> {
            VoyageStockDistributeDO stockDistributeDO = new VoyageStockDistributeDO();
            stockDistributeDO.setVoyageId(item.getVoyageId());
            stockDistributeDO.setRoomModelId(item.getRoomModelId());
            stockDistributeDO.setRoomModelName(item.getRoomModelName());
            stockDistributeDO.setFloor(item.getFloor());
            stockDistributeDO.setNum(BigDecimal.ZERO);
            stockDistributeDO.setDistributorType(DistributorTypeEnum.OTC.getType());
            stockDistributeDO.setDistributorTypeName(DistributorTypeEnum.OTC.getName());
            stockDistributeDO.setDistributorId(null);
            stockDistributeDO.setStoreId(null);
            stockDistributeDO.setShipId(voyage.getShipId());
            list.add(stockDistributeDO);
        });

        //OTA分销商类型的分销商数据
        List<DistributorRespDTO> otaDistributorList = otaDistributorApi.getDistributorList(DistributorTypeEnum.OTA.getType());
        otaDistributorList.stream().forEach(distributor -> {
            stockDetailList.stream().forEach(item -> {
                VoyageStockDistributeDO stockDistributeDO = new VoyageStockDistributeDO();
                stockDistributeDO.setVoyageId(item.getVoyageId());
                stockDistributeDO.setRoomModelId(item.getRoomModelId());
                stockDistributeDO.setRoomModelName(item.getRoomModelName());
                stockDistributeDO.setFloor(item.getFloor());
                stockDistributeDO.setNum(BigDecimal.ZERO);
                stockDistributeDO.setDistributorType(DistributorTypeEnum.OTA.getType());
                stockDistributeDO.setDistributorTypeName(DistributorTypeEnum.OTA.getName());
                stockDistributeDO.setDistributorId(distributor.getId());
                stockDistributeDO.setDistributorName(distributor.getName());
                stockDistributeDO.setStoreId(null);
                stockDistributeDO.setShipId(voyage.getShipId());
                list.add(stockDistributeDO);
            });
        });
        //旅行社分销商类型的分销商数据
        List<DistributorRespDTO> otcDistributorList = otaDistributorApi.getDistributorList(DistributorTypeEnum.OTC.getType());
        Map<Long, DistributorRespDTO> otcIdDistributorMap = CollectionUtils.convertMap(otcDistributorList, DistributorRespDTO::getId);
        otcDistributorList.stream().forEach(distributor -> {
            stockDetailList.stream().forEach(item -> {
                VoyageStockDistributeDO stockDistributeDO = new VoyageStockDistributeDO();
                stockDistributeDO.setVoyageId(item.getVoyageId());
                stockDistributeDO.setRoomModelId(item.getRoomModelId());
                stockDistributeDO.setRoomModelName(item.getRoomModelName());
                stockDistributeDO.setFloor(item.getFloor());
                stockDistributeDO.setNum(BigDecimal.ZERO);
                stockDistributeDO.setDistributorType(DistributorTypeEnum.OTC.getType());
                stockDistributeDO.setDistributorTypeName(DistributorTypeEnum.OTC.getName());
                stockDistributeDO.setDistributorId(distributor.getId());
                stockDistributeDO.setDistributorName(distributor.getName());
                stockDistributeDO.setStoreId(null);
                stockDistributeDO.setShipId(voyage.getShipId());
                list.add(stockDistributeDO);
            });
        });
        //获取旅行社门店的库存数据
        List<StoreInfoRespDTO> storeList = storeApi.getStoreList();
        storeList.stream().forEach(store -> {
            stockDetailList.stream().forEach(item -> {
                VoyageStockDistributeDO stockDistributeDO = new VoyageStockDistributeDO();
                stockDistributeDO.setVoyageId(item.getVoyageId());
                stockDistributeDO.setRoomModelId(item.getRoomModelId());
                stockDistributeDO.setRoomModelName(item.getRoomModelName());
                stockDistributeDO.setFloor(item.getFloor());
                stockDistributeDO.setNum(BigDecimal.ZERO);
                stockDistributeDO.setDistributorType(DistributorTypeEnum.OTC.getType());
                stockDistributeDO.setDistributorTypeName(DistributorTypeEnum.OTC.getName());
                stockDistributeDO.setDistributorId(store.getAgencyId());
                stockDistributeDO.setDistributorName(otcIdDistributorMap.get(store.getAgencyId()).getName());
                stockDistributeDO.setStoreId(store.getId());
                stockDistributeDO.setStoreName(store.getStoreName());
                stockDistributeDO.setShipId(voyage.getShipId());
                list.add(stockDistributeDO);
            });
        });
        return list;
    }

    @Override
    public VoyageStockDistributeTotalRespVO getVoyageStockDistributeTotal(Long voyageId) {
        VoyageStockDistributeTotalRespVO resp = new VoyageStockDistributeTotalRespVO();
        List<VoyageStockDistributeTotalRespVO.TotalGroupByDistributorVO> totalGroupByDistributorList = voyageStockDistributeMapper.selectListGroupByDistributor(voyageId);
        resp.setTotalGroupByDistributorList(totalGroupByDistributorList);
        List<VoyageStockDistributeTotalRespVO.TotalGroupByRoomModelFloorVO> totalGroupByRoomModelFloorList = voyageStockDistributeMapper.selectListGroupByRoomModelFloor(voyageId);
        resp.setTotalGroupByRoomModelFloorList(totalGroupByRoomModelFloorList);
        return resp;
    }

    @Override
    public List<RoomRespDTO> getRoomList(Long voyageId) {
        VoyageDO voyage = voyageService.getVoyage(voyageId);
        if(voyage == null) {
            throw exception(ErrorCodeConstants.VOYAGE_NOT_EXISTS);
        }
        List<RoomRespDTO> roomList = roomApi.getRoomList(voyage.getShipId());
        List<VoyageStockDistributeDO> list = voyageStockDistributeMapper.selectListByVoyageId(voyageId);
        List<Integer> selectedList = list.stream().flatMap(list1 -> {
            List<Integer> roomNums = list1.getRoomNums();
            if(roomNums != null) {
                return roomNums.stream();
            }
            return new ArrayList<Integer>().stream();
        }).collect(Collectors.toList());
        roomList.stream().forEach(room -> {
            room.setIsSelected(selectedList.contains(room.getRoomNum()));
        });
        return roomList;
    }

    @Override
    public List<RoomRespDTO> getCanSelectRoomList(QueryCanSelectRoomListReqVO reqVO) {
        Long voyageId = reqVO.getVoyageId();
        VoyageDO voyage = voyageService.getVoyage(voyageId);
        if(voyage == null) {
            throw exception(ErrorCodeConstants.VOYAGE_NOT_EXISTS);
        }
        List<RoomRespDTO> roomList = roomApi.getRoomList(voyage.getShipId());
        List<VoyageStockDistributeDO> list = voyageStockDistributeMapper.selectList(reqVO);
        List<Integer> canSelectList = list.stream().flatMap(list1 -> {
            List<Integer> roomNums = list1.getRoomNums();
            if(roomNums != null) {
                return roomNums.stream();
            }
            return new ArrayList<Integer>().stream();
        }).collect(Collectors.toList());
        List<RoomRespDTO> result = roomList.stream().filter(room -> canSelectList.contains(room.getRoomNum())).collect(Collectors.toList());
        return result;
    }

    @Override
    public List<VoyageStockDistributeDO> getVoyageStockDistributeDetail(VoyageStockDistributeReqVO reqVO) {
        return voyageStockDistributeMapper.selectDetailList(reqVO);
    }


}