package com.fjhx.service.order.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
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.base.BaseEntity;
import com.fjhx.constants.ExcelImportBusinessType;
import com.fjhx.constants.SystemConfigKeyConstant;
import com.fjhx.entity.customer.CustomerInfo;
import com.fjhx.entity.order.OrderDetails;
import com.fjhx.entity.order.OrderInfo;
import com.fjhx.entity.product.ProductInfo;
import com.fjhx.mapper.order.OrderInfoMapper;
import com.fjhx.params.order.OrderDetailsEx;
import com.fjhx.params.order.OrderInfoEx;
import com.fjhx.params.order.OrderInfoVo;
import com.fjhx.params.order.OrderJdExcelVo;
import com.fjhx.service.excel.ExcelImportLogService;
import com.fjhx.service.flow.CompensateFlowService;
import com.fjhx.service.order.OrderDetailsService;
import com.fjhx.service.order.OrderInfoService;
import com.fjhx.service.product.ProductInfoService;
import com.fjhx.service.system.SystemConfigService;
import com.fjhx.uitl.code.CodeEnum;
import com.fjhx.utils.Assert;
import com.fjhx.utils.RegionClientUtil;
import com.fjhx.utils.wrapperUtil.IWrapper;
import com.fjhx.utils.wrapperUtil.KeywordData;
import org.springblade.core.excel.util.ExcelUtil;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.utils.AuthUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

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

/**
 * <p>
 * 销售订单 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-12-13
 */
@Service
public class OrderInfoInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderDetailsService orderDetailsService;

    @Autowired
    private ExcelImportLogService excelImportLogService;

    @Autowired
    private ProductInfoService productInfoService;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private CompensateFlowService compensateFlowService;


    @Override
    public Page<OrderInfoEx> getPage(Map<String, Object> condition) {

        IWrapper<Object> wrapper = IWrapper.getWrapper(condition)
                // 京东订单销售订单
                .func(q -> {
                    Integer type = Convert.toInt(condition.get("type"));
                    Boolean issue = Convert.toBool(condition.get("deliverable"), false);
                    Boolean afterSales = Convert.toBool(condition.get("afterSales"), false);

                    // 如果类型为空，默认为销售订单
                    if (type == null) {
                        // 如果是出货
                        if (issue) {
                            q.in("oi", OrderInfo::getType, 1, 2, 5, 6);
                        }
                        // 如果是售后
                        else if (afterSales) {
                            q.in("oi", OrderInfo::getType, 4, 5, 6);
                        }
                        // 默认销售订单
                        else {
                            q.in("oi", OrderInfo::getType, 1, 2);
                        }
                    } else {
                        q.eq("oi", OrderInfo::getType);
                    }

                    // 如果是出货，订单状态为1进行中，出库状态为1未出库或2进行中
                    if (issue) {
                        q.eq("oi", OrderInfo::getStatus, 1);
                        q.in("oi", OrderInfo::getIssueStatus, 1, 2);
                    }
                })
                .keyword(new KeywordData("oi", OrderInfo::getCode), new KeywordData("ci", CustomerInfo::getName))
                .eq("oi", OrderInfo::getAfterSalesStatus)
                .eq("oi", OrderInfo::getStatus)
                .like("oi", OrderInfo::getCode)
                .like("ci", CustomerInfo::getName, condition.get("customerName"))
                .eq("oi", OrderInfo::getCountryId)
                .eq("oi", OrderInfo::getProvinceId)
                .eq("oi", OrderInfo::getCityId)
                .ge("oi", OrderInfo::getAmountMoney, condition.get("minAmountMoney"))
                .le("oi", OrderInfo::getAmountMoney, condition.get("maxAmountMoney"))
                .orderByDesc("oi", OrderInfo::getId);

        Page<OrderInfoEx> page = baseMapper.getPage(createPage(condition), wrapper);

        // 赋值国省市
        RegionClientUtil.setEntityRegionName(page.getRecords());

        return page;
    }

    @Override
    public void add(OrderInfoVo orderVo) {
        // 订单明细
        List<OrderDetails> orderDetailsList = orderVo.getOrderDetailsList();
        Assert.notEmpty(orderDetailsList, "订单明细不能为空");

        Integer type = orderVo.getType();
        if (type == 3) {
            // 获取京东客户id
            Long jdCustomerId = systemConfigService.getValue(SystemConfigKeyConstant.JD_CUSTOMER_ID, Long.class);
            orderVo.setCustomerInfoId(jdCustomerId);
        }

        // 订单时间
        orderVo.setOrderTime(ObjectUtil.defaultIfNull(orderVo.getOrderTime(), new Date()));

        // 统计订单金额
        BigDecimal amountMoney = orderDetailsList.stream()
                .map(item -> item.getPrice().multiply(item.getQuantity())).reduce(BigDecimal.ZERO, BigDecimal::add);
        orderVo.setAmountMoney(amountMoney);

        orderVo.setStatus(1);
        orderVo.setIssueStatus(1);

        synchronized (this) {
            if (type == 3) {
                orderVo.setCode(CodeEnum.ORDER_JD.getCode(orderVo.getCode()));
            } else {
                orderVo.setCode(CodeEnum.ORDER_SALES.getCode(orderVo.getCode()));
            }
            save(orderVo);
        }

        // 添加订单明细
        for (OrderDetails orderDetails : orderDetailsList) {
            orderDetails.setOrderId(orderVo.getId());
            orderDetails.setNotIssuedQuantity(orderDetails.getQuantity());
        }
        orderDetailsService.saveBatch(orderDetailsList);
    }

    @Override
    public void edit(OrderInfoVo orderVo) {
        updateById(orderVo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long excelImport(MultipartFile file) {

        long start = System.currentTimeMillis();

        long flag = IdWorker.getId();

        // 读取excel数据
        List<OrderJdExcelVo> list = ExcelUtil.read(file, OrderJdExcelVo.class);

        // 获取京东客户id
        Long jdCustomerId = systemConfigService.getValue(SystemConfigKeyConstant.JD_CUSTOMER_ID, Long.class);

        // 验证订单编号是否重复
        verifyOrderNumber(list);

        // 查询产品编码对应的产品id
        Map<String, Long> codeIdMap = getCodeIdMap(list);

        // 保存导入记录
        excelImportLogService.saveLog(flag, ExcelImportBusinessType.JD_ORDER, file);

        // 京东订单表
        Map<String, OrderInfo> map = new HashMap<>();

        // 京东订单明细
        List<OrderDetails> orderDetailsList = new ArrayList<>();

        Date date = new Date();

        for (OrderJdExcelVo orderJdExcelVo : list) {

            String code = orderJdExcelVo.getCode();
            String productCode = orderJdExcelVo.getProductCode();
            BigDecimal price = orderJdExcelVo.getPrice();
            BigDecimal quantity = orderJdExcelVo.getQuantity();

            Long productId = codeIdMap.get(productCode);
            OrderInfo orderInfo = map.get(code);
            if (orderInfo == null) {
                orderInfo = new OrderInfoEx();

                long id = IdWorker.getId();
                orderInfo.setId(id);
                orderInfo.setType(3);
                orderInfo.setCustomerInfoId(jdCustomerId);
                orderInfo.setCode(code);
                orderInfo.setAmountMoney(price.multiply(quantity));
                orderInfo.setOrderTime(orderJdExcelVo.getOrderTime());
                orderInfo.setStatus(1);
                orderInfo.setCountryId("China");
                orderInfo.setDetailedAddress(orderJdExcelVo.getDetailedAddress());
                orderInfo.setContacts(orderJdExcelVo.getContacts());
                orderInfo.setPhone(orderJdExcelVo.getPhone());
                orderInfo.setExcelImportId(flag);
                orderInfo.setCreateUser(AuthUtil.getUserId());
                orderInfo.setCreateTime(date);
                orderInfo.setDistributionCenter(orderJdExcelVo.getDistributionCenter());
                orderInfo.setJdWarehouse(orderJdExcelVo.getJdWarehouse());

                map.put(code, orderInfo);
            } else {
                orderInfo.setAmountMoney(orderInfo.getAmountMoney().add(price.multiply(quantity)));
            }

            OrderDetails orderDetails = new OrderDetails();
            orderDetails.setOrderId(orderInfo.getId());
            orderDetails.setProductId(productId);
            orderDetails.setQuantity(quantity);
            orderDetails.setPrice(price);
            orderDetails.setNotIssuedQuantity(quantity);

            orderDetailsList.add(orderDetails);
        }

        saveBatch(new ArrayList<>(map.values()));
        orderDetailsService.saveBatch(orderDetailsList);

        // 保存导入记录
        excelImportLogService.editLog(start, flag, 1);

        return flag;
    }

    @Override
    public List<OrderInfo> getOrderByCustomerId(Long customerInfoId) {
        Assert.notEmpty(customerInfoId, "客户id不能为空");

        return list(q -> q
                .select(BaseEntity::getId, OrderInfo::getCode)
                .eq(OrderInfo::getCustomerInfoId, customerInfoId)
                .in(OrderInfo::getType, 1, 2)
                .orderByDesc(BaseEntity::getId)
        );
    }

    @Override
    public OrderInfoEx getDetails(Long id) {
        Assert.notEmpty(id, "订单id不能为空");
        QueryWrapper<OrderInfo> wrapper = Wrappers.query();
        wrapper.eq("oi.id", id);
        OrderInfoEx orderInfoEx = baseMapper.getDetails(wrapper);
        // 赋值国省市
        RegionClientUtil.setEntityRegionName(orderInfoEx);

        List<OrderDetailsEx> orderDetailsExes = orderDetailsService.listByOrderSalesId(id);

        orderInfoEx.setOrderDetailsList(orderDetailsExes);
        return orderInfoEx;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addAfterSales(OrderInfoVo orderInfoVo) {
        Long oldId = orderInfoVo.getId();

        OrderInfo orderInfo = getById(oldId);
        orderInfo.setId(null);
        orderInfo.setType(orderInfoVo.getType());
        orderInfo.setStatus(1);
        orderInfo.setIssueStatus(1);
        orderInfo.setAfterSalesStatus(1);
        orderInfo.setRemark(orderInfoVo.getRemark());
        save(orderInfo);

        if (orderInfoVo.getType().equals(4)) {
            compensateFlowService.create(orderInfoVo);
        }

        List<OrderDetails> list = orderDetailsService.list(q -> q.eq(OrderDetails::getOrderId, oldId));
        for (OrderDetails orderDetails : list) {
            orderDetails.setId(null);
            orderDetails.setOrderId(orderInfo.getId());
            orderDetails.setNotIssuedQuantity(orderDetails.getQuantity());
        }
        orderDetailsService.saveBatch(list);
    }

    /**
     * 验证订单编号是否重复
     */
    private void verifyOrderNumber(List<OrderJdExcelVo> list) {
        List<String> codeList = list.stream().map(OrderJdExcelVo::getCode).distinct().collect(Collectors.toList());
        List<String> existCodeList = listObj(OrderInfo::getCode, q -> q.in(OrderInfo::getCode, codeList));

        if (existCodeList.size() > 0) {
            StringJoiner joiner = new StringJoiner(",");
            existCodeList.forEach(joiner::add);
            throw new ServiceException("存在相同的采购单号:" + joiner);
        }
    }


    /**
     * 获取<产品编码，产品id>map
     */
    private Map<String, Long> getCodeIdMap(List<OrderJdExcelVo> list) {
        List<String> productCodeList = list.stream().map(OrderJdExcelVo::getProductCode).distinct().collect(Collectors.toList());
        Map<String, Long> kv = productInfoService.getKV(
                ProductInfo::getCode,
                BaseEntity::getId,
                q -> q.in(ProductInfo::getCode, productCodeList));

        if (kv.size() != productCodeList.size()) {
            StringJoiner joiner = new StringJoiner(",");

            for (String productCode : productCodeList) {
                if (kv.get(productCode) == null) {
                    joiner.add(productCode);
                }
            }
            throw new ServiceException("产品表中未找到对应产品编码:" + joiner);
        }
        return kv;
    }

}
