package com.fjhx.purchase.service.subscribe.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.entity.product.vo.ProductInfoVo;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.item.util.excel.util.ExcelUtil;
import com.fjhx.purchase.entity.purchase.po.Purchase;
import com.fjhx.purchase.entity.purchase.po.PurchaseDetail;
import com.fjhx.purchase.entity.purchase.vo.PurchaseDetailVo;
import com.fjhx.purchase.entity.subscribe.SubscribeDetailExcelBo;
import com.fjhx.purchase.entity.subscribe.dto.SubscribeDetailDto;
import com.fjhx.purchase.entity.subscribe.dto.SubscribeDetailSelectDto;
import com.fjhx.purchase.entity.subscribe.po.Subscribe;
import com.fjhx.purchase.entity.subscribe.po.SubscribeDetail;
import com.fjhx.purchase.entity.subscribe.vo.SubscribeDetailVo;
import com.fjhx.purchase.mapper.subscribe.SubscribeDetailMapper;
import com.fjhx.purchase.service.purchase.PurchaseDetailService;
import com.fjhx.purchase.service.subscribe.SubscribeDetailService;
import com.fjhx.tenant.entity.dict.dto.DictTenantDataSelectDto;
import com.fjhx.tenant.entity.dict.vo.DictTenantDataVo;
import com.fjhx.tenant.service.dict.DictTenantDataService;
import com.fjhx.wms.entity.warehouse.po.Warehouse;
import com.fjhx.wms.service.warehouse.WarehouseService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.common.utils.wrapper.SqlField;
import com.ruoyi.system.service.ISysRoleService;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

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


/**
 * <p>
 * 申购单 服务实现类
 * </p>
 *
 * @author
 * @since 2023-04-03
 */
@DS(SourceConstant.PURCHASE)
@Service
public class SubscribeDetailServiceImpl extends ServiceImpl<SubscribeDetailMapper, SubscribeDetail> implements SubscribeDetailService {

    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    WarehouseService warehouseService;
    @Autowired
    PurchaseDetailService purchaseDetailService;

    @Autowired
    private DictTenantDataService dictTenantDataService;
    @Autowired
    private ISysRoleService sysRoleService;

    /**
     * 分页
     *
     * @param dto
     * @return
     */
    @Override
    public Page<SubscribeDetailVo> getPage(SubscribeDetailSelectDto dto) {
        IWrapper<SubscribeDetail> wrapper = getWrapper();
        //申购单号
        wrapper.like(ObjectUtil.isNotEmpty(dto.getCode()), "t2.code", dto.getCode());

        //申购时间
        wrapper.ge(ObjectUtil.isNotEmpty(dto.getBeginTime()), "t2.create_time", dto.getBeginTime());
        wrapper.ge(ObjectUtil.isNotEmpty(dto.getEndTime()), "t2.create_time", dto.getEndTime());
        wrapper.ge(ObjectUtil.isNotEmpty(dto.getSubscribeStatus()), "t2.subcribe_status", dto.getSubscribeStatus());

        if (ObjectUtil.isNotEmpty(dto.getStatus())) {
            wrapper.in("t1", SubscribeDetail::getStatus, Arrays.asList(dto.getStatus().split(",")));
        }

        wrapper.eq("pi.definition", dto.getDefinition());
        wrapper.keyword(dto.getKeyword(),
                new SqlField("t2", Subscribe::getCode),
                new SqlField("pi", ProductInfo::getCustomCode),
                new SqlField("pi", ProductInfo::getName)
        );

        // 维多利亚扩展根据到货仓库id过滤
        wrapper.eq("json_unquote(t2.victoriatourist_json -> '$.receiptWarehouseId')", dto.getReceiptWarehouseId());
        if (ObjectUtil.isNotEmpty(dto.getDeptId())) {
            wrapper.eq("json_unquote(pi.victoriatourist_json -> '$.deptId')", dto.getDeptId().toString());
        }
        //待采购过滤掉指定状态 例如不要 99 作废
        if (ObjectUtil.isNotEmpty(dto.getNeStatus())) {
            wrapper.notIn("t1", SubscribeDetail::getStatus, dto.getNeStatus().split(","));
        }

        if (ObjectUtil.isNotEmpty(dto.getSubStatus())) {
            //已采购为0
            if (1 == dto.getSubStatus()) {
                wrapper.eq("(SELECT IF ( sum( pd.count ) IS NULL, 0, sum( pd.count )) FROM purchase_detail pd WHERE pd.subscribe_detail_id = t1.id)", 0);
            }
            //已采购大于0小于申购数
            if (2 == dto.getSubStatus()) {
                wrapper.gt("(SELECT IF ( sum( pd.count ) IS NULL, 0, sum( pd.count )) FROM purchase_detail pd WHERE pd.subscribe_detail_id = t1.id)", 0);
                wrapper.eq("((SELECT IF ( sum( pd.count ) IS NULL, 0, sum( pd.count )) FROM purchase_detail pd WHERE pd.subscribe_detail_id = t1.id)<t1.count)", 1);
            }
            //采购数大于等于申购数
            if (3 == dto.getSubStatus()) {
                wrapper.eq("((SELECT IF ( sum( pd.count ) IS NULL, 0, sum( pd.count )) FROM purchase_detail pd WHERE pd.subscribe_detail_id = t1.id)>=t1.count)", 1);
            }
        }

        //没有自定义排序就默认按申购时间倒序
        if (ObjectUtil.isEmpty(dto.getSubscribeTimeSort()) && ObjectUtil.isEmpty(dto.getProductNameSort())) {
            wrapper.orderByDesc("t1", SubscribeDetail::getCreateTime);
        }
        //申购时间排序
        if (ObjectUtil.isNotEmpty(dto.getSubscribeTimeSort())) {
            if (1 == dto.getSubscribeTimeSort()) {
                wrapper.orderByAsc("t1", SubscribeDetail::getCreateTime);
            } else {
                wrapper.orderByDesc("t1", SubscribeDetail::getCreateTime);
            }
        }
        //产品名称排序
        if (ObjectUtil.isNotEmpty(dto.getProductNameSort())) {
            if (1 == dto.getProductNameSort()) {
                wrapper.orderByAsc("pi.name");
            } else {
                wrapper.orderByDesc("pi.name");
            }
        }

        //添加权限过滤
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        Set<String> permissionList = sysRoleService.selectRolePermissionByUserId(SecurityUtils.getUserId());
        DynamicDataSourceContextHolder.poll();
        if (ObjectUtil.isNotEmpty(permissionList)) {
            //if当前用户的角色 in [运营专员, 运营助理] 页面仅展示产品.管理部门 == 当前用户所在部门或下级部门的相关数据
            if (permissionList.contains("E-commerce operation") || permissionList.contains("Operation assistant")) {
                wrapper.and(q -> q.eq("de.dept_id", SecurityUtils.getDeptId())
                        .or()
                        .like("de.ancestors", SecurityUtils.getDeptId()));
            }
        }

        Page<SubscribeDetailVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<SubscribeDetailVo> list = page.getRecords();

        if (list.size() == 0) {
            return page;
        }

        //赋值已采购数量
        List<Long> subscribeDetailIds = list.stream().map(SubscribeDetail::getId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(subscribeDetailIds)) {
            List<PurchaseDetailVo> purchaseDetailsList = purchaseDetailService.getDetail(IWrapper.<PurchaseDetail>getWrapper()
                    .in("pd", PurchaseDetail::getSubscribeDetailId, subscribeDetailIds)
                    .in("p", Purchase::getPurchaseStatus, 10, 30)
            );

            Map<Long, List<PurchaseDetail>> purchaseDetailsMap = purchaseDetailsList.stream().collect(Collectors.groupingBy(PurchaseDetail::getSubscribeDetailId));
            for (SubscribeDetailVo subscribeDetailVo : list) {
                List<PurchaseDetail> purchaseDetails = purchaseDetailsMap.get(subscribeDetailVo.getId());
                if (ObjectUtil.isEmpty(purchaseDetails)) {
                    subscribeDetailVo.setPurchaseCount(BigDecimal.ZERO);
                    continue;
                }
                BigDecimal count = purchaseDetails.stream()
                        .map(PurchaseDetail::getCount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                subscribeDetailVo.setPurchaseCount(count);
            }
        }

        return page;
    }

    @Override
    public Page<SubscribeDetailVo> getPageByWdly(SubscribeDetailSelectDto dto) {
        Page<SubscribeDetailVo> page = getPage(dto);
        List<SubscribeDetailVo> records = page.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return page;
        }

        //获取到货仓库id列表
        List<Long> wids = new ArrayList<>();
        for (SubscribeDetailVo subscribeDetailVo : records) {
            String victoriatouristJson = subscribeDetailVo.getVictoriatouristJson();
            if (ObjectUtil.isNotEmpty(victoriatouristJson)) {
                JSONObject json = JSONObject.parseObject(victoriatouristJson);
                wids.add(json.getLong("receiptWarehouseId"));
            }
        }
        //获取到货仓库信息
        List<Warehouse> warehouses = new ArrayList<>();
        if (ObjectUtil.isNotEmpty(wids)) {
            warehouses = warehouseService.listByIds(wids);
        }
        Map<Long, String> warehousesMap = warehouses.stream().collect(Collectors.toMap(Warehouse::getId, Warehouse::getName));

        for (SubscribeDetailVo subscribeDetailVo : records) {
            //赋值到货仓库名称
            String victoriatouristJson = subscribeDetailVo.getVictoriatouristJson();
            if (ObjectUtil.isNotEmpty(victoriatouristJson)) {
                JSONObject json = JSONObject.parseObject(victoriatouristJson);
                json.put("receiptWarehouseName", warehousesMap.get(json.getLong("receiptWarehouseId")));
                subscribeDetailVo.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
            }
        }

        return page;
    }

    /**
     * 根据IDS获取明细
     *
     * @param ids
     * @return
     */
    @Override
    public List<SubscribeDetailVo> detail(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new ServiceException("参数异常");
        }
        List<SubscribeDetailVo> list = baseMapper.getDetail(ids);
        if (CollectionUtils.isNotEmpty(list)) {
            //根据申购businessId取出所有产品
            List<Long> productIds = list.stream().map(SubscribeDetail::getBussinessId).collect(Collectors.toList());
            List<ProductInfoVo> productInfoVos = productInfoService.getListByProductIds(productIds);
            Map<Long, List<ProductInfoVo>> productMap = productInfoVos.stream().collect(Collectors.groupingBy(ProductInfoVo::getId));
            for (SubscribeDetailVo s : list) {
                if (MapUtils.isNotEmpty(productMap)) {
                    ProductInfoVo p = productMap.get(s.getBussinessId()).get(0);
                    s.setProductCategory(p.getClassifyName());
                    s.setProductCode(p.getCode());
                    s.setProductUnit(p.getUnit());
                    s.setProductType(p.getType());
                    s.setProductName(p.getName());
                    s.setProductSpec(p.getSpec());
                    s.setProductCustomCode(p.getCustomCode());
                    s.setProductDefinition(p.getDefinition());

                    //维多利亚赋值部门id
                    String victoriatouristJson = p.getVictoriatouristJson();
                    JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
                    s.setDeptId(json.getLong("deptId"));
                }
            }
        }
        return list;
    }

    @Override
    public void add(SubscribeDetailDto subscribeDetailDto) {
        this.save(subscribeDetailDto);
    }

    @Override
    public void edit(SubscribeDetailDto subscribeDetailDto) {
        this.updateById(subscribeDetailDto);
    }

    @Override
    public void delete(Long id) {
        this.removeById(id);
    }

    /**
     * 申购统计（申购单分页）
     */
    @Override
    public Map<String, Object> subscribeStatistics(SubscribeDetailSelectDto dto) {
        //存放申购统计数据
        Map<String, Object> map = new HashMap<>();

        //存放申购统计详情数据
        List<Map<String, Object>> list = new ArrayList<>();

        QueryWrapper<Object> query = Wrappers.query();
        query.groupBy("pi.type");
        //查询申购统计（产品类型分组）
        List<SubscribeDetailVo> subscribeDetailVos = baseMapper.subscribeStatistics(query);
        Map<String, List<SubscribeDetailVo>> subscribeDetailVoMap = subscribeDetailVos.stream()
                .collect(Collectors.groupingBy(SubscribeDetailVo::getType));

        //计算申购笔合计数据
        Integer amount = subscribeDetailVos.stream().map(SubscribeDetailVo::getCounts).reduce(Integer::sum).orElse(0);
        map.put("amount", amount);
        //计算申购货品种类合计数据
        Integer typeAmount = subscribeDetailVos.stream().map(SubscribeDetailVo::getTypeCount).reduce(Integer::sum).orElse(0);
        map.put("typeAmount", typeAmount);
        //切换数据源
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        //获取产品类型字典数据
        List<DictTenantDataVo> dictTenantDataVoList = getDict("product_type");
        DynamicDataSourceContextHolder.poll();

        if (ObjectUtil.isEmpty(dictTenantDataVoList)) {
            throw new ServiceException("数据有误：产品没有配置产品类型字典，请先添加产品类型字典");
        }

        //赋值笔数、货品种类数据
        for (DictTenantDataVo dictTenantDataVo : dictTenantDataVoList) {
            //设置初始值
            Map<String, Object> typeMap = new HashMap<>();
            typeMap.put("type", dictTenantDataVo.getDictValue());
            typeMap.put("count", 0);
            typeMap.put("typeCount", 0);

            //赋值
            List<SubscribeDetailVo> subscribeDetailVoList = subscribeDetailVoMap.get(dictTenantDataVo.getDictKey());
            if (ObjectUtil.isNotEmpty(subscribeDetailVoList)) {
                typeMap.put("count", subscribeDetailVoList.get(0).getCounts());
                typeMap.put("typeCount", subscribeDetailVoList.get(0).getTypeCount());
            }
            list.add(typeMap);
        }
        map.put("productTypeList", list);
        return map;
    }

    //根据字典编码获取字典的数据
    private List<DictTenantDataVo> getDict(String code) {
        DictTenantDataSelectDto dto = new DictTenantDataSelectDto();
        dto.setDictCode(code);
        return dictTenantDataService.getList(dto);
    }

    /**
     * 申购明细Excel导入
     */
    @Override
    public List<SubscribeDetailExcelBo> excelImport(MultipartFile file) {
        List<SubscribeDetailExcelBo> excelBoList = ExcelUtil.read(file, SubscribeDetailExcelBo.class);
        if (ObjectUtil.isEmpty(excelBoList)) {
            return excelBoList;
        }
        List<String> productCodes = excelBoList.stream().map(SubscribeDetailExcelBo::getProductCustomCode).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(productCodes)) {
            List<String> notArr = new ArrayList<>();
            //赋值产品信息
            Map<String, ProductInfo> productInfoMap = productInfoService.mapKEntity(ProductInfo::getCustomCode, q -> q.in(ProductInfo::getCustomCode, productCodes));
            for (SubscribeDetailExcelBo subscribeDetailExcelBo : excelBoList) {
                ProductInfo productInfo = productInfoMap.get(subscribeDetailExcelBo.getProductCustomCode());
                if (ObjectUtil.isEmpty(productInfo)) {
                    notArr.add(subscribeDetailExcelBo.getProductCustomCode());
                    continue;
                }
                subscribeDetailExcelBo.setBussinessId(productInfo.getId());
                subscribeDetailExcelBo.setProductDefinition(productInfo.getDefinition());
                subscribeDetailExcelBo.setProductName(productInfo.getName());
                subscribeDetailExcelBo.setProductSpec(productInfo.getSpec());
                subscribeDetailExcelBo.setProductUnit(productInfo.getUnit());
            }
            if (notArr.size() != 0) {
                throw new ServiceException("以下产品不存在：" + notArr.stream().collect(Collectors.joining(",")));
            }
        }
        return excelBoList;
    }

}
