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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import com.tmerclub.cloud.api.delivery.feign.AreaFeignClient;
import com.tmerclub.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.tmerclub.cloud.api.multishop.vo.ShopDetailVO;
import com.tmerclub.cloud.api.order.feign.AllotOrderFeignClient;
import com.tmerclub.cloud.api.order.feign.PurchaseOrderFeignClient;
import com.tmerclub.cloud.api.product.dto.WarehouseDTO;
import com.tmerclub.cloud.api.product.feign.SkuStockFeignClient;
import com.tmerclub.cloud.api.product.feign.SpuFeignClient;
import com.tmerclub.cloud.api.product.feign.StockPointFeignClient;
import com.tmerclub.cloud.api.supplier.feign.SupplierDetailFeignClient;
import com.tmerclub.cloud.api.supplier.vo.SupplierApiDetailVO;
import com.tmerclub.cloud.common.cache.constant.CacheNames;
import com.tmerclub.cloud.common.cache.constant.ProductCacheNames;
import com.tmerclub.cloud.common.cache.util.RedisUtil;
import com.tmerclub.cloud.common.constant.Constant;
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.dto.AreaDTO;
import com.tmerclub.cloud.common.order.vo.WarehouseVO;
import com.tmerclub.cloud.common.product.vo.StockPointVO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.PrincipalUtil;
import com.tmerclub.cloud.product.constant.DistributedIdKey;
import com.tmerclub.cloud.product.dto.WarehouseAreaDTO;
import com.tmerclub.cloud.product.mapper.TakeStockMapper;
import com.tmerclub.cloud.product.mapper.WarehouseMapper;
import com.tmerclub.cloud.product.model.Warehouse;
import com.tmerclub.cloud.product.service.WarehouseAreaService;
import com.tmerclub.cloud.product.service.WarehouseService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 *
 *
 * @author tmerclub
 * @date 2023-11-08 11:11:44
 */
@Service
public class WarehouseServiceImpl implements WarehouseService {

    @Autowired
    private WarehouseMapper warehouseMapper;
    @Autowired
    private WarehouseAreaService warehouseAreaService;
    @Autowired
    private TakeStockMapper takeStockMapper;
    @DubboReference
    private SpuFeignClient spuFeignClient;
    @Autowired
    private SegmentManager segmentManager;
    @DubboReference
    private StockPointFeignClient stockPointFeignClient;
    @DubboReference
    private SkuStockFeignClient skuStockFeignClient;
    @DubboReference
    private ShopDetailFeignClient shopDetailFeignClient;
    @DubboReference
    private SupplierDetailFeignClient supplierDetailFeignClient;
    @DubboReference
    private AreaFeignClient areaFeignClient;
    @DubboReference
    private AllotOrderFeignClient allotOrderFeignClient;
    @DubboReference
    private PurchaseOrderFeignClient purchaseOrderFeignClient;

    @Override
    public PageVO<WarehouseVO> page(PageDTO pageDTO, WarehouseDTO warehouseDTO) {
        PageVO<WarehouseVO> pageVO = PageUtil.doPage(pageDTO, () -> warehouseMapper.list(warehouseDTO));
        if (pageVO.getList().size() == 0) {
            return pageVO;
        }
        if (Objects.nonNull(warehouseDTO.getSkuId())) {
            List<Long> warehouseIds = pageVO.getList().stream().map(WarehouseVO::getWarehouseId).collect(Collectors.toList());
            Map<Long, Integer> stockMap = skuStockFeignClient.getStockMapBySkuIdAndStockPointIds(warehouseDTO.getSkuId(), warehouseIds).getData();
            for (WarehouseVO warehouseVO : pageVO.getList()) {
                warehouseVO.setStock(stockMap.containsKey(warehouseVO.getWarehouseId()) ? stockMap.get(warehouseVO.getWarehouseId()) : 0);
            }
        }
        for (WarehouseVO warehouseVO : pageVO.getList()) {
            if (StrUtil.isNotBlank(warehouseVO.getPhone()) && PrincipalUtil.isMobile(warehouseVO.getPhone())) {
                warehouseVO.setPhone(PhoneUtil.hideBetween(warehouseVO.getPhone()).toString());
            }
        }
        return pageVO;
    }

    @Override
    @Cacheable(cacheNames = ProductCacheNames.WAREHOUSE_BY_ID_PREFIX, key = "#warehouseId", sync = true)
    public WarehouseVO getByWarehouseId(Long warehouseId) {
        WarehouseVO warehouse = warehouseMapper.getByWarehouseId(warehouseId);
        if (warehouse == null) {
            return null;
        }
        List<Long> areaIds = warehouseMapper.getWarehouseAreaByWarehouseId(warehouseId);
        warehouse.setCityList(areaFeignClient.listByAreaIdList(areaIds));
        return warehouse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertWarehouseAndArea(WarehouseDTO warehouseDTO) {
        this.checkIsRepeat(warehouseDTO);
        Warehouse warehouse = BeanUtil.map(warehouseDTO, Warehouse.class);
        if (Objects.isNull(warehouseDTO.getWarehouseId())) {
            warehouse.setWarehouseId(segmentManager.getSegmentId(DistributedIdKey.tmerclub_STOCK_POINT));
        }
        warehouse.setCreateTime(new Date());
        warehouse.setUpdateTime(new Date());
        // 插入仓库
        warehouseMapper.save(warehouse);
        // 插入供应城市数据
        insertWarehouseArea(warehouse.getWarehouseId(), warehouseDTO.getCityList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = ProductCacheNames.WAREHOUSE_BY_ID_PREFIX, key = "#warehouseDTO.warehouseId")
    public void updateWarehouseAndArea(WarehouseDTO warehouseDTO) {
        WarehouseVO warehouseDb = warehouseMapper.getByWarehouseId(warehouseDTO.getWarehouseId());
        this.checkIsRepeat(warehouseDTO);
        if (!Objects.equals(warehouseDb.getShopId(), warehouseDTO.getShopId())) {
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        if (!PrincipalUtil.isDbPhone(warehouseDTO.getPhone(), warehouseDb.getPhone(), true)) {
            throw new LuckException("请输入正确的手机号");
        }
        if (warehouseDTO.getPhone().contains(Constant.ASTERISK)) {
            warehouseDTO.setPhone(warehouseDb.getPhone());
        }
        // 更新运费模板
        warehouseMapper.update(BeanUtil.map(warehouseDTO, Warehouse.class));
        // 删除供应城市
        warehouseAreaService.deleteByWarehouseId(warehouseDTO.getWarehouseId());
        // 添加供应城市关系
        insertWarehouseArea(warehouseDTO.getWarehouseId(), warehouseDTO.getCityList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public WarehouseVO deleteWarehouseAndArea(Long warehouseId) {
        WarehouseVO warehouseVO = warehouseMapper.getByWarehouseId(warehouseId);
        if (warehouseVO.getType() == 0) {
            throw new LuckException("默认仓库不能删除");
        }
        // 检查库存
        int count = stockPointFeignClient.countStockList(warehouseId).getData();
        if (count > 0) {
            throw new LuckException("存在商品库存，不可删除");
        }
        // 检查采购订单
        Long unFinishCount = purchaseOrderFeignClient.countUnFinish(warehouseId);
        if (unFinishCount > 0) {
            throw new LuckException("存在未完成的采购订单，不可删除");
        }
        // 检查调拨订单
        unFinishCount = allotOrderFeignClient.countUnFinish(warehouseId);
        if (unFinishCount > 0) {
            throw new LuckException("存在未完成的调拨订单，不可删除");
        }
        // 检查实物盘点
        unFinishCount = takeStockMapper.countUnFinish(warehouseId);
        if (unFinishCount > 0) {
            throw new LuckException("存在未完成的实物盘点，不可删除");
        }
        warehouseAreaService.deleteByWarehouseId(warehouseId);
        // 删除运费模板
        warehouseMapper.deleteById(warehouseId);
        return warehouseVO;
    }

    @Override
    public void removeWarehouseCache(Long warehouseId, Long shopId, Integer sysType) {
        List<String> keys = new ArrayList<>(Constant.TWO);
        if (Objects.nonNull(warehouseId)) {
            keys.add(CacheNames.WAREHOUSE_BY_ID_PREFIX + CacheNames.UNION + warehouseId);
        }
        keys.add(CacheNames.WAREHOUSE_BY_ID_PREFIX + CacheNames.UNION + warehouseId);
        keys.add(CacheNames.SHOP_WAREHOUSE_LIST_PREFIX + CacheNames.UNION + shopId + CacheNames.UNION_KEY + sysType);
        RedisUtil.deleteBatch(keys);
    }

    @Override
    public void createWarehouseByShopId(Long shopId, Integer sysType, String phone, String name) {
        Warehouse warehouse = new Warehouse();
        warehouse.setWarehouseId(segmentManager.getSegmentId(DistributedIdKey.tmerclub_STOCK_POINT));
        warehouse.setShopId(shopId);
        warehouse.setSysType(sysType);
        warehouse.setType(0);
        warehouse.setWarehouseName("默认仓库");
        warehouse.setPhone(phone);
        warehouse.setManage(name);
        warehouse.setCreateTime(new Date());
        warehouse.setUpdateTime(new Date());
        warehouseMapper.save(warehouse);
    }

    @Override
    public List<Long> listWarehouseAreaByShopId(Long shopId, Integer sysType, Long warehouseId) {
        return warehouseMapper.listareaByShopIdAndSysType(shopId, sysType, warehouseId);
    }

    @Override
    public List<WarehouseVO> listWarehouse(WarehouseDTO warehouseDTO) {;
        return warehouseMapper.list(warehouseDTO);
    }

    @Override
    public List<WarehouseVO> listCanDeliveryWarehouse(WarehouseDTO warehouseDTO) {
        // 按areaId获取可配送的仓库（区域仓库和默认仓库都查出来）
        List<WarehouseVO> warehouses = warehouseMapper.listCanDeliveryWarehouse(warehouseDTO);
        // 区分区域仓库和默认仓库
        Set<Long> shopIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        List<WarehouseVO> areaWarehouses = new ArrayList<>(Constant.INITIAL_CAPACITY);
        List<WarehouseVO> defaultWarehouses = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (WarehouseVO warehouse : warehouses) {
            if (Objects.equals(warehouse.getType(), 0)) {
                defaultWarehouses.add(warehouse);
            } else {
                areaWarehouses.add(warehouse);
                shopIds.add(warehouse.getShopId());
            }
        }
        // 若店铺的可配送的区域仓库不存在则使用默认仓库
        for (WarehouseVO defaultWarehouse : defaultWarehouses) {
            if (shopIds.add(defaultWarehouse.getShopId())) {
                areaWarehouses.add(defaultWarehouse);
            }
        }
        return areaWarehouses;
    }

    @Override
    public WarehouseVO getDefaultWarehouseByShopId(Long shopId, Integer sysType) {
        return warehouseMapper.getDefaultWarehouseIdByShopId(shopId,sysType);
    }

    @Override
    @Cacheable(cacheNames = CacheNames.SHOP_WAREHOUSE_LIST_PREFIX, key = "#shopId + ':' + #sysType")
    public List<WarehouseVO> listWarehouseByShopId(Long shopId, Integer sysType) {
        List<WarehouseVO> warehouseVOS = warehouseMapper.listWarehouseByShopId(shopId, sysType);
        // 将默认仓库放到第一位
        warehouseVOS.sort(Comparator.comparing(WarehouseVO::getType));
        return warehouseVOS;
    }

    @Override
    public void intiWarehouse() {
        List<Warehouse> warehouseList = new ArrayList<>();
        WarehouseDTO warehouseDTO = new WarehouseDTO();
        warehouseDTO.setSysType(SysTypeEnum.MULTISHOP.value());
        warehouseDTO.setType(0);
        List<WarehouseVO> list = warehouseMapper.list(warehouseDTO);
        List<Long> shopIds = list.stream().map(WarehouseVO::getShopId).toList();
        // 初始化店铺默认仓库
        List<ShopDetailVO> shopList = shopDetailFeignClient.listShopIds().getData();

        if (CollectionUtil.isNotEmpty(shopList)) {
            shopList.forEach(shop-> {
                if (shopIds.contains(shop.getShopId())) {
                    return;
                }
                Warehouse warehouse = new Warehouse();
                warehouse.setShopId(shop.getShopId());
                warehouse.setManage(shop.getContactName());
                warehouse.setPhone(shop.getContactPhone());
                warehouse.setSysType(SysTypeEnum.MULTISHOP.value());
                warehouseList.add(warehouse);
            });
        }
        // 初始化供应商默认仓库
        warehouseDTO.setSysType(SysTypeEnum.SUPPLIER.value());
        list = warehouseMapper.list(warehouseDTO);
        List<Long> supplierIds = list.stream().map(WarehouseVO::getShopId).toList();
        List<SupplierApiDetailVO> supplierList = supplierDetailFeignClient.listSupplierIds().getData();
        if (CollectionUtil.isNotEmpty(supplierList)) {
            supplierList.forEach(supplier-> {
                if (supplierIds.contains(supplier.getSupplierId())) {
                    return;
                }
                Warehouse warehouse = new Warehouse();
                warehouse.setShopId(supplier.getSupplierId());
                warehouse.setManage(supplier.getContactName());
                warehouse.setPhone(supplier.getContactPhone());
                warehouse.setSysType(SysTypeEnum.SUPPLIER.value());
                warehouseList.add(warehouse);
            });
        }
        if (warehouseList.size() != 0) {
            warehouseList.forEach( s-> {
                s.setWarehouseId(segmentManager.getSegmentId(DistributedIdKey.tmerclub_STOCK_POINT));
                s.setWarehouseName("默认仓库");
                s.setType(0);
            });
            warehouseMapper.batchSave(warehouseList);
        }
    }

    @Override
    public List<WarehouseVO> listDefaultWarehouses() {
        return warehouseMapper.listDefaultWarehouses();
    }

    @Override
    public StockPointVO getWarehousePoint(Long shopId, Integer sysType) {
        StockPointVO stockPointVO = new StockPointVO();
        List<WarehouseVO> warehouseVOS = warehouseMapper.listWarehouseByShopId(shopId, sysType);
        stockPointVO.setWarehouseSize(warehouseVOS.size());
        for (WarehouseVO warehouseVO : warehouseVOS) {
            if (warehouseVO.getType() == 0) {
                stockPointVO.setDefaultWarehouseId(warehouseVO.getWarehouseId());
                break;
            }
        }
        return stockPointVO;
    }

    private void checkIsRepeat(WarehouseDTO warehouseDTO) {
        int count = warehouseMapper.countByWarehouseName(warehouseDTO.getShopId(), warehouseDTO.getWarehouseName(), warehouseDTO.getSysType(), warehouseDTO.getWarehouseId());
        if (count > 0) {
            throw new LuckException("仓库名称已存在，请重新输入");
        }
        // 查询是否已经存在重复供应城市，一个城市只能有一个区域仓库
        if (warehouseDTO.getType() == 1) {
            if (CollectionUtil.isEmpty(warehouseDTO.getCityList())) {
                throw new LuckException("区域仓库必须要有供应城市");
            }
            List<Long> cityList = warehouseMapper.listareaByShopIdAndSysType(warehouseDTO.getShopId(), warehouseDTO.getSysType(), warehouseDTO.getWarehouseId());
            if (CollectionUtil.isNotEmpty(cityList)) {
                for (AreaDTO areaDTO : warehouseDTO.getCityList()) {
                    if (cityList.contains(areaDTO.getAreaId())) {
                        throw new LuckException(areaDTO.getAreaName() + " 已有区域仓库，请重新选择");
                    }
                }
            }
        }
    }

    private void insertWarehouseArea(Long warehouseId, List<AreaDTO> areaDTOList) {
        List<WarehouseAreaDTO> warehouseAreaList = new ArrayList<>(areaDTOList.size());
        for (AreaDTO areaDTO : areaDTOList) {
            WarehouseAreaDTO warehouseAreaDTO = new WarehouseAreaDTO();
            warehouseAreaDTO.setWarehouseId(warehouseId);
            warehouseAreaDTO.setAreaId(areaDTO.getAreaId());
            warehouseAreaList.add(warehouseAreaDTO);
        }
        warehouseAreaService.batchSave(warehouseAreaList);
    }
}
