
package com.tmerclub.cloud.delivery.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.api.delivery.dto.StationSalesDTO;
import com.tmerclub.cloud.api.delivery.vo.StationVO;
import com.tmerclub.cloud.api.product.dto.WarehouseDTO;
import com.tmerclub.cloud.api.product.dto.WarehouseSearchDTO;
import com.tmerclub.cloud.api.product.feign.TakeStockFeignClient;
import com.tmerclub.cloud.api.product.feign.WarehouseFeignClient;
import com.tmerclub.cloud.common.database.util.PageAdapter;
import com.tmerclub.cloud.common.order.vo.*;
import com.tmerclub.cloud.api.feign.SearchOrderFeignClient;
import com.tmerclub.cloud.api.order.constant.OrderStatus;
import com.tmerclub.cloud.api.product.feign.SkuStockFeignClient;
import com.tmerclub.cloud.api.product.feign.StockPointFeignClient;
import com.tmerclub.cloud.api.product.vo.SkuStockVO;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.constant.SysTypeEnum;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.leaf.manager.SegmentManager;
import com.tmerclub.cloud.common.order.constant.StockModeEnum;
import com.tmerclub.cloud.common.order.dto.AreaDTO;
import com.tmerclub.cloud.common.order.dto.OrderSearchDTO;
import com.tmerclub.cloud.common.product.constant.SpuMold;
import com.tmerclub.cloud.common.product.vo.StockPointSkuVO;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.util.Arith;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.common.util.PrincipalUtil;
import com.tmerclub.cloud.constant.DistributedIdKey;
import com.tmerclub.cloud.delivery.bo.StationOrderBO;
import com.tmerclub.cloud.api.delivery.constant.StationStockStatus;
import com.tmerclub.cloud.delivery.dto.OrderStationDTO;
import com.tmerclub.cloud.delivery.dto.StationDTO;
import com.tmerclub.cloud.delivery.mapper.StationMapper;
import com.tmerclub.cloud.delivery.model.Station;
import com.tmerclub.cloud.delivery.service.StationService;
import com.tmerclub.cloud.order.service.AllotOrderService;
import com.tmerclub.cloud.order.service.PurchaseOrderService;
import com.tmerclub.cloud.order.vo.StationDetailVO;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 自提点信息
 *
 * @author tmerclub
 * @date 2020-12-07 15:10:01
 */
@Service
public class StationServiceImpl implements StationService {

    @Autowired
    private StationMapper stationMapper;
    @Autowired
    private AllotOrderService allotOrderService;
    @Lazy
    @Autowired
    private PurchaseOrderService purchaseOrderService;
    @DubboReference
    private SearchOrderFeignClient searchOrderFeignClient;
    @Autowired
    private SegmentManager segmentManager;
    @DubboReference
    private SkuStockFeignClient skuStockFeignClient;
    @DubboReference
    private WarehouseFeignClient warehouseFeignClient;
    @DubboReference
    private StockPointFeignClient stockPointFeignClient;
    @DubboReference
    private TakeStockFeignClient takeStockFeignClient;

    private static final int TEN = 10;
    private static final int TWELVE = 12;
    private static final int EIGHTEEN = 18;
    private static final int THIRTY = 30;

    @Override
    public PageVO<StationVO> page(PageDTO pageDTO) {
        return PageUtil.doPage(pageDTO, () -> stationMapper.list());
    }

    @Override
    public PageVO<StationVO> pageStation(PageDTO pageDTO, StationDTO stationDTO) {
        PageVO<StationVO> pageVO = PageUtil.doPage(pageDTO, () -> stationMapper.listStation(stationDTO));
        if (pageVO.getList().size() == 0) {
            return pageVO;
        }
        if (Objects.nonNull(stationDTO.getSkuId())) {
            List<Long> stationIds = pageVO.getList().stream().map(StationVO::getStationId).collect(Collectors.toList());
            Map<Long, Integer> stockMap = skuStockFeignClient.getStockMapBySkuIdAndStockPointIds(stationDTO.getSkuId(), stationIds).getData();
            for (StationVO stationVO : pageVO.getList()) {
                stationVO.setStock(stockMap.containsKey(stationVO.getStationId()) ? stockMap.get(stationVO.getStationId()) : 0);
            }
        }
        return pageVO;
    }

    @Override
    public StationVO getByStationId(Long stationId) {
        return stationMapper.getByStationId(stationId);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void save(Station station) {
        station.setStationId(segmentManager.getSegmentId(DistributedIdKey.tmerclub_STOCK_POINT));
        stationMapper.save(station);
        // 创建一个门店仓库
        this.saveStationWarehouse(station);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void update(Station station) {
        // 更新门店仓库
        this.updateStationWarehouse(station);
        station.setStockMode(null);
        stationMapper.update(station);
    }

    @Override
    public void deleteById(Long stationId) {
        stationMapper.deleteById(stationId);
        // 删除仓库
        this.deleteStationWarehouse(stationId);
    }

    @Override
    public void logicDeleteById(Long stationId) {
        stationMapper.logicDeleteById(stationId);
    }

    @Override
    public List<StationSalesDTO> getStationSalesRecord(Long shopId, Long stationId) {
        // es订单检索数据准备
        OrderSearchDTO orderSearchDTO = new OrderSearchDTO();
        orderSearchDTO.setStationId(stationId);
        orderSearchDTO.setGtePayTime(true);
        orderSearchDTO.setStatusList(Arrays.asList(
                OrderStatus.PAYED.value(),
                OrderStatus.CONSIGNMENT.value(),
                OrderStatus.SUCCESS.value(),
                OrderStatus.WAIT_GROUP.value())
        );
        Date day = DateUtil.beginOfDay(new Date());
        Date month = DateUtil.beginOfMonth(day);
        // 查询"当月"自提门店订单信息
        orderSearchDTO.setPayTime(month);
        List<EsOrderVO> esOrders = searchOrderFeignClient.listEsOrder(orderSearchDTO).getData();
        List<StationOrderBO> monthOrders = this.esOrderToStationOrder(esOrders, stationId);
        // 通过数据过滤，获取“当日”自提门店订单信息
        List<StationOrderBO> dayOrders = new ArrayList<>(16);
        if (!CollectionUtils.isEmpty(monthOrders)) {
            monthOrders.sort((o1, o2) -> o2.getPayTime().compareTo(o1.getPayTime()));
            for (StationOrderBO order : monthOrders) {
                if (order.getPayTime().compareTo(day) < 0) {
                    break;
                }
                dayOrders.add(order);
            }
        }
        // 数据统计
        StationSalesDTO daySalesDTO = this.calStationSales(dayOrders);
        daySalesDTO.setSalesType(1);
        StationSalesDTO monthSalesDTO = this.calStationSales(monthOrders);
        monthSalesDTO.setSalesType(2);
        return Arrays.asList(daySalesDTO, monthSalesDTO);
    }

    /**
     * es订单转成自提门店订单
     *
     * @return
     */
    private List<StationOrderBO> esOrderToStationOrder(List<EsOrderVO> esOrders, Long stationId) {
        List<StationOrderBO> stationOrders = new ArrayList<>(Constant.INITIAL_CAPACITY);
        StationOrderBO stationOrder;
        long prodPrice;
        // 遍历转换成门店订单数据
        for (EsOrderVO esOrder : esOrders) {
            stationOrder = new StationOrderBO();
            stationOrder.setUserId(esOrder.getUserId());
            stationOrder.setPayTime(esOrder.getPayTime());
            stationOrder.setAmount(0L);
            if (CollectionUtils.isEmpty(esOrder.getOrderVirtualInfoList())) {
                // 门店自提订单 [收益 = 订单实际金额 + 平台优惠金额]
                stationOrder.setAmount(esOrder.getActualTotal() + esOrder.getPlatformAmount());
            } else {
                // 虚拟核销订单 [核销单次收益 = (订单实际金额+平台优惠金额) / 订单商品数量]
                prodPrice = (long) Arith.div(Arith.add(esOrder.getActualTotal(), esOrder.getPlatformAmount()), esOrder.getAllCount(), 0);
                for (OrderVirtualInfoVO orderVirtualInfo : esOrder.getOrderVirtualInfoList()) {
                    if (Objects.equals(orderVirtualInfo.getStationId(), stationId)) {
                        stationOrder.setAmount(stationOrder.getAmount() + prodPrice);
                    }
                }
            }
            stationOrders.add(stationOrder);
        }
        return stationOrders;
    }

    /**
     * 统计数据
     *
     * @param orders
     * @return
     */
    private StationSalesDTO calStationSales(List<StationOrderBO> orders) {
        StationSalesDTO stationSalesDTO = new StationSalesDTO();
        Set<Long> userIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        double payAmount = 0.0;
        double customerUnitPrice = 0.0;
        int orderNum = 0;
        if (!CollectionUtils.isEmpty(orders)) {
            orderNum += orders.size();
            for (StationOrderBO order : orders) {
                userIds.add(order.getUserId());
                payAmount = Arith.add(payAmount, order.getAmount());
            }
            customerUnitPrice = Arith.div(payAmount, userIds.size(), 2);
        }
        // 赋值
        stationSalesDTO.setPayAmount(payAmount);
        stationSalesDTO.setPayOrderNumber(orderNum);
        stationSalesDTO.setUserNum(userIds.size());
        stationSalesDTO.setCustomerUnitPrice(customerUnitPrice);
        return stationSalesDTO;
    }

    @Override
    public PageVO<StationDetailVO> getStationList(PageDTO page, OrderStationDTO orderStationDTO) {
        // 要判断门店是否有库存，所以先查询所有的门店列表
        List<StationDetailVO> shopStationList = stationMapper.listSimpleStation(orderStationDTO.getShopId(), StatusEnum.ENABLE.value());
        // 没有门店，直接返回null
        if (CollUtil.isEmpty(shopStationList)) {
            PageVO<StationDetailVO> pageVO = new PageVO<>();
            pageVO.setTotal(0L);
            pageVO.setPages(0);
            return pageVO;
        }


        // 有库存，可以自提的门店id列表
        Set<Long> stationSet = stationStockSet(orderStationDTO.getStationSpuList(), shopStationList, orderStationDTO.getShopId());
        // 查询门店列表及计算距离
        List<StationDetailVO> stationList = stationMapper.getStationList(new PageAdapter(page), orderStationDTO);
        // 组装门店列表数据
        PageVO<StationDetailVO> stationPage = new PageVO<>();
        stationPage.setTotal((long) shopStationList.size());
        stationPage.setList(stationList);
        stationPage.setPages(PageUtil.getPages(stationPage.getTotal(), page.getPageSize()));
        // 拆分处理门店列表的数据
        handleStationOrderInfo(stationSet, stationList);
        return stationPage;
    }

    @Override
    public StationVO getStationInfoById(Long stationId) {
        return stationMapper.getByStationId(stationId);
    }

    @Override
    public Double getStationDistance(Long stationId, Double lat, Double lng) {
        return stationMapper.getStationDistance(stationId, lat, lng);
    }

    @Override
    public List<StationVO> listByStationId(List<Long> stationIds) {
        if (CollUtil.isEmpty(stationIds)) {
            return new ArrayList<>();
        }
        return stationMapper.getStationListById(stationIds);
    }

    @Override
    public List<StationVO> listByShopId(Long shopId) {
        StationDTO stationDTO = new StationDTO();
        stationDTO.setShopId(shopId);
        stationDTO.setStockMode(StockModeEnum.SINGLE_STOCK.value());
        return stationMapper.listStation(stationDTO);
    }

    /**
     * 创建门店仓库
     * @param station 门店
     */
    private void saveStationWarehouse(Station station) {
        WarehouseDTO warehouseDTO = this.buildWarehouseDTO(station);
        // warehouseId和stationId一样
        warehouseDTO.setWarehouseId(station.getStationId());
        warehouseFeignClient.insertWarehouseAndArea(warehouseDTO);
    }

    /**
     * 更新门店仓库
     * @param station 门店
     */
    private void updateStationWarehouse(Station station) {
        StationVO dbStation = stationMapper.getByStationId(station.getStationId());
        // "门店名称"或"地址"或"联系电话"更改后才更新仓库数据
        boolean isUpdate = !Objects.equals(dbStation.getStationName(), station.getStationName())
                || !Objects.equals(dbStation.getAreaId(), station.getAreaId())
                || !Objects.equals(dbStation.getMobile(), station.getMobile());
        if (!isUpdate) {
            return;
        }
        if (Objects.nonNull(station.getMobile()) && !PrincipalUtil.isDbPhone(station.getMobile(), dbStation.getMobile(), false)) {
            throw new LuckException("请输入正确的手机号");
        }
        if (Objects.isNull(station.getMobile()) || station.getMobile().contains(Constant.ASTERISK)) {
            station.setMobile(dbStation.getMobile());
        }
        WarehouseSearchDTO searchParam = new WarehouseSearchDTO();
        searchParam.setShopId(station.getStationId());
        searchParam.setSysType(SysTypeEnum.STATION.value());
        List<WarehouseVO> warehouses = warehouseFeignClient.listWarehouse(searchParam);
        if (CollectionUtils.isEmpty(warehouses)) {
            this.saveStationWarehouse(station);
            return;
        }
        WarehouseDTO warehouseDTO = this.buildWarehouseDTO(station);
        warehouseDTO.setWarehouseId(warehouses.get(0).getWarehouseId());
        warehouseFeignClient.updateWarehouseAndArea(warehouseDTO);
    }

    /**
     * 删除门店仓库
     * @param stationId 门店id
     */
    private void deleteStationWarehouse(Long stationId) {
        WarehouseSearchDTO searchParam = new WarehouseSearchDTO();
        searchParam.setShopId(stationId);
        searchParam.setSysType(SysTypeEnum.STATION.value());
        List<WarehouseVO> warehouses = warehouseFeignClient.listWarehouse(searchParam);
        if (!CollectionUtils.isEmpty(warehouses)) {
            warehouseFeignClient.deleteWarehouseAndArea(warehouses.get(0).getWarehouseId());
        }
    }

    /**
     * 构建仓库DTO
     * @param station 门店
     * @return 仓库dto
     */
    private WarehouseDTO buildWarehouseDTO(Station station) {
        WarehouseDTO warehouseDTO = new WarehouseDTO();
        BeanUtils.copyProperties(station, warehouseDTO);
        warehouseDTO.setShopId(station.getStationId());
        warehouseDTO.setSysType(SysTypeEnum.STATION.value());
        warehouseDTO.setWarehouseName(station.getStationName());
        warehouseDTO.setType(1);
        warehouseDTO.setPhone(station.getMobile());
        warehouseDTO.setAddress(station.getAddr());
        List<AreaDTO> areas = new ArrayList<>();
        areas.add(new AreaDTO(station.getAreaId(), null, null, null));
        warehouseDTO.setCityList(areas);
        return warehouseDTO;
    }

    @Override
    public void switchStationStockMode(Long stationId, Integer type) {
        Integer stockMode;
        Station station = new Station();
        station.setStationId(stationId);
        if (Objects.nonNull(type)) {
            stockMode = StockModeEnum.ALL_STOCK.value();
        } else {
            stockMode = StockModeEnum.SINGLE_STOCK.value();
        }
        station.setStockMode(stockMode);
        stationMapper.update(station);
        // 更新库存
        skuStockFeignClient.updateStockMode(stationId, stockMode, type);
        // 切换成共享库存时，需作废调拨订单，采购订单和实物盘点
        if (Objects.equals(stockMode, StockModeEnum.ALL_STOCK.value())) {
            WarehouseSearchDTO warehouseSearchDTO = new WarehouseSearchDTO();
            warehouseSearchDTO.setShopId(stationId);
            warehouseSearchDTO.setSysType(SysTypeEnum.STATION.value());
            List<WarehouseVO> warehouseVOS = warehouseFeignClient.listWarehouse(warehouseSearchDTO);
            if (CollectionUtils.isEmpty(warehouseVOS)) {
                return;
            }
            Long warehouseId = warehouseVOS.get(0).getWarehouseId();
            // 作废调拨
            allotOrderService.nullifyOrderByWarehouseId(warehouseId);
            // 作废采购
            purchaseOrderService.nullifyByWarehouseId(warehouseId);
            // 作废实物盘点
            takeStockFeignClient.nullifyByWarehouseId(warehouseId);
        }
    }

    @Override
    public OrderSelfStationVO getOrderStation(UserDeliveryInfoVO userDeliveryInfoVO, List<OrderStationSpuDTO> orderStationSpuList) {
        OrderStationDTO orderStationDTO = new OrderStationDTO();
        orderStationDTO.setStationId(userDeliveryInfoVO.getStationId());
        OrderSelfStationVO orderSelfStationVO = userDeliveryInfoVO.getOrderSelfStation();
        orderStationDTO.setLat(orderSelfStationVO.getLat());
        orderStationDTO.setLng(orderSelfStationVO.getLng());
        orderStationDTO.setShopId(userDeliveryInfoVO.getDvyTypes().get(0).getShopId());

        // 要判断门店是否有库存，所以先查询所有的门店列表
        List<StationDetailVO> shopStationList = stationMapper.listSimpleStation(orderStationDTO.getShopId(), StatusEnum.ENABLE.value());
        // 没有门店，直接返回null
        if (CollUtil.isEmpty(shopStationList)) {
            // 没有门店列表
            orderSelfStationVO.setStationStockStatus(StationStockStatus.NOT_STATION_LIST.getStatus());
            return orderSelfStationVO;
        }
        Set<Long> stationSet = stationStockSet(orderStationSpuList, shopStationList, orderStationDTO.getShopId());


        // 有门店，但所有门店的库存数量都不足时，返回一个状态为库存不足的门店，代表当前区域库存不足
        if (CollUtil.isEmpty(stationSet)) {
            // 门店没有库存
            orderSelfStationVO.setStationStockStatus(StationStockStatus.NOT_STOCK.getStatus());
            return orderSelfStationVO;
        }
        // 存在库存充足的门店
        orderStationDTO.setStationIds(new ArrayList<>(stationSet));
        List<StationDetailVO> stationList = stationMapper.getStationList(new PageAdapter(1,1), orderStationDTO);
        if (CollUtil.isEmpty(stationList)) {
            // 门店没有库存
            orderSelfStationVO.setStationStockStatus(StationStockStatus.NOT_STOCK.getStatus());
            return orderSelfStationVO;
        }
        StationDetailVO stationDetailVO = stationList.get(0);
        orderSelfStationVO.setStationId(stationDetailVO.getStationId());
        orderSelfStationVO.setStationName(stationDetailVO.getStationName());
        orderSelfStationVO.setStationImgUrl(stationDetailVO.getImgUrl());
        return orderSelfStationVO;
    }

    private static void handleStationOrderInfo(Set<Long> stationSet, List<StationDetailVO> stationList) {
        for (StationDetailVO stationParam : stationList) {
            double distance = 0L;
            if (Objects.nonNull(stationParam.getDistance())) {
                distance = stationParam.getDistance();
            }
            stationParam.setDistance(distance);
            String timeDate = stationParam.getTimeInfo();
            StationDetailVO.TimeInfoModeVO timeInfoModeVO = Json.parseObject(timeDate, StationDetailVO.TimeInfoModeVO.class);
            Long[] shopTime = timeInfoModeVO.getShopTime();
            String startTime = DateUtil.format(new Date(shopTime[0]), "HH:mm");
            String endTime = DateUtil.format(new Date(shopTime[1]), "HH:mm");
            stationParam.setBusiness(startTime + "-" + endTime);
            // 自提门店的库存是否充足
            stationParam.setHasStock(stationSet.contains(stationParam.getStationId()) ? 1 : 0);
        }
    }

    private Set<Long> stationStockSet(List<OrderStationSpuDTO> orderStationSpuList, List<StationDetailVO> shopStationList, Long shopId) {
        // 库存模式是共享总部库存， 或者包含虚拟商品，需要查询默认库存
        List<WarehouseVO> warehousedList = warehouseFeignClient.listWarehouseByShopId(shopId, SysTypeEnum.MULTISHOP.value());
        long defaultStockPointId = warehousedList.get(0).getWarehouseId();
        List<StockPointSkuVO> stockPointSkuVOList = new ArrayList<>(orderStationSpuList.size() * shopStationList.size());
        for (OrderStationSpuDTO orderStationSpuDTO : orderStationSpuList) {
            // 商品类别是虚拟商品，使用默认库存
            if (Objects.equals(orderStationSpuDTO.getSpuMold(), SpuMold.VIRTUAL.value())) {
                stockPointSkuVOList.add(new StockPointSkuVO(orderStationSpuDTO.getSkuId(), defaultStockPointId));
                continue;
            }
            for (StationDetailVO stationDetailVO : shopStationList) {
                if (Objects.equals(stationDetailVO.getStockMode(), StockModeEnum.ALL_STOCK.value())) {
                    stockPointSkuVOList.add(new StockPointSkuVO(orderStationSpuDTO.getSkuId(), defaultStockPointId));
                } else {
                    stockPointSkuVOList.add(new StockPointSkuVO(orderStationSpuDTO.getSkuId(), stationDetailVO.getStationId()));
                }
            }
        }
        ServerResponseEntity<Map<String, SkuStockVO>> stockServerResponseEntity = skuStockFeignClient.mapSkuPointStockByStockPoints(stockPointSkuVOList);
        if (!stockServerResponseEntity.isSuccess()) {
            throw new LuckException(stockServerResponseEntity.getMsg());
        }
        Map<String, SkuStockVO> stockMap = stockServerResponseEntity.getData();
        // 有库存，可以自提的门店id列表
        Set<Long> stationSet = new HashSet<>(shopStationList.size());
        for (StationDetailVO stationDetailVO : shopStationList) {
            // 判断门店库存是否充足
            if (!checkStationStock(orderStationSpuList, defaultStockPointId, stockMap, stationDetailVO)) {
                continue;
            }
            stationSet.add(stationDetailVO.getStationId());
        }
        return stationSet;
    }


    private static boolean checkStationStock(List<OrderStationSpuDTO> orderStationSpuList, long defaultStockPointId, Map<String, SkuStockVO> stockMap, StationDetailVO stationParam) {
        for (OrderStationSpuDTO orderStationSpuDTO : orderStationSpuList) {
            long pointId = defaultStockPointId;
            // 独立仓库并且不是虚拟商品，才能使用门店库存
            if (Objects.equals(stationParam.getStockMode(), StockModeEnum.SINGLE_STOCK.value()) && !Objects.equals(orderStationSpuDTO.getSpuMold(), SpuMold.VIRTUAL.value())) {
                pointId = stationParam.getStationId();
            }
            SkuStockVO skuStockVO = stockMap.get(orderStationSpuDTO.getSkuId() + Constant.UNDERLINE + pointId);
            if (skuStockVO.getStock() < orderStationSpuDTO.getCount()) {
                return false;
            }
        }
        return true;
    }

}
