package com.hys.app.service.erp.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hys.app.converter.erp.OrderReturnConverter;
import com.hys.app.converter.erp.OrderReturnItemConverter;
import com.hys.app.framework.context.user.AdminUserContext;
import com.hys.app.framework.database.WebPage;
import com.hys.app.framework.database.mybatisplus.base.BaseServiceImpl;
import com.hys.app.framework.exception.ServiceException;
import com.hys.app.framework.rabbitmq.MessageSender;
import com.hys.app.framework.rabbitmq.MqMessage;
import com.hys.app.framework.util.BeanUtils;
import com.hys.app.framework.util.CurrencyUtil;
import com.hys.app.framework.util.DateUtil;
import com.hys.app.framework.util.PageConvert;
import com.hys.app.mapper.erp.OrderReturnMapper;
import com.hys.app.model.base.rabbitmq.AmqpExchange;
import com.hys.app.model.erp.dos.*;
import com.hys.app.model.erp.dto.OrderReturnDTO;
import com.hys.app.model.erp.dto.OrderReturnItemDTO;
import com.hys.app.model.erp.dto.OrderReturnQueryParams;
import com.hys.app.model.erp.dto.OrderReturnStatisticsQueryParam;
import com.hys.app.model.erp.dto.message.OrderReturnAuditPassMessage;
import com.hys.app.model.erp.enums.*;
import com.hys.app.model.erp.vo.*;
import com.hys.app.model.system.dos.AdminUser;
import com.hys.app.model.system.dos.DeptDO;
import com.hys.app.service.erp.*;
import com.hys.app.service.system.AdminUserManager;
import com.hys.app.service.system.DeptManager;
import com.hys.app.util.ValidateUtil;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.function.Function;

import static com.hys.app.framework.util.CollectionUtils.convertList;
import static com.hys.app.framework.util.CollectionUtils.convertMap;

/**
 * 订单退货业务层实现
 *
 * @author 张崧
 * @since 2023-12-14 15:42:07
 */
@Service
@AllArgsConstructor
public class OrderReturnManagerImpl extends BaseServiceImpl<OrderReturnMapper, OrderReturnDO> implements OrderReturnManager {
    private OrderReturnConverter converter;
    private OrderReturnItemConverter itemConverter;
    private OrderReturnItemManager orderReturnItemManager;
    private OrderManager orderManager;
    private OrderItemManager orderItemManager;
    private NoGenerateManager noGenerateManager;
    private OrderReturnMapper orderReturnMapper;
    private GoodsManager goodsManager;
    private ProductManager productManager;

    @Override
    public WebPage<OrderReturnVO> list(OrderReturnQueryParams queryParams) {
        return converter.convert(baseMapper.selectPage(queryParams));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(OrderReturnDTO orderReturnDTO) {
        OrderDO aDo = orderManager.getById(orderReturnDTO.getOrderId());
        if (ObjectUtil.isNull(aDo)) {
            throw new ServiceException("要发起售后的订单不存在");
        }
        if (SaleOrderStatusEnum.SALE_AFTER_END.equals(aDo.getStatus())) {
            throw new ServiceException("一个订单只能做一次售后");
        }
        //判断要退货的商品有没有超过订单数量的商品
        for (OrderReturnItemDTO dto : orderReturnDTO.getItemList()) {
            OrderItemDO itemDO = orderItemManager.getById(dto.getOrderItemId());
            if (ObjectUtil.isNull(itemDO)) {
                throw new ServiceException("退货的商品必须在订单里");
            }
            if (itemDO.getNum() < dto.getReturnNum()) {
                throw new ServiceException("退貨的数量不能大于原订单的物品数量");
            }
            itemDO.setReturnNum(itemDO.getReturnNum()+dto.getReturnNum());
            itemDO.setHasSaleAfter(true);
            orderItemManager.updateById(itemDO);
        }

        //更改订单的状态
        aDo.setStatus(SaleOrderStatusEnum.SALE_AFTER_ING);
        orderManager.updateById(aDo);
        //新增售后订单主题
        OrderReturnDO returnDO = BeanUtil.copyProperties(orderReturnDTO, OrderReturnDO.class);
        returnDO.setSn(noGenerateManager.generate(NoBusinessTypeEnum.OrderReturn, 66L));
        save(returnDO);
        // 保存退货单明细
        List<OrderReturnItemDO> itemBean = BeanUtils.toBean(orderReturnDTO.getItemList(), OrderReturnItemDO.class);
        itemBean.forEach(item -> item.setOrderReturnId(returnDO.getId()));
        orderReturnItemManager.saveBatch(itemBean);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(OrderReturnDTO orderReturnDTO) {
        //还原原订单的数据
        OrderReturnDO oldDO = getById(orderReturnDTO.getId());
        // 保存退货单
        OrderReturnDO orderReturnDO = converter.combination(orderReturnDTO);
        updateById(orderReturnDO);
        // 保存退货单明细
//        List<OrderReturnItemDO> itemList = itemConverter.combination(orderReturnDO.getId(), orderReturnDTO);
//        orderReturnItemManager.deleteByOrderReturnId(Collections.singletonList(orderReturnDTO.getId()));
//        orderReturnItemManager.saveBatch(itemList);
    }

    @Override
    public OrderReturnVO getDetail(String id) {
        OrderReturnVO orderReturnVO = converter.convert(getById(id));
        List<OrderReturnItemVO> convert = itemConverter.convert(orderReturnItemManager.listByOrderReturnId(id));
        for (OrderReturnItemVO vo : convert) {
            ProductVO productVO = BeanUtil.copyProperties(productManager.getById(vo.getProductId()), ProductVO.class);
            vo.setProductVO(productVO);
            GoodsDO goodsDO = goodsManager.getById(productVO.getGoodsId());
            vo.setGoodsVO(BeanUtil.copyProperties(goodsDO, GoodsVO.class));
        }
        orderReturnVO.setItemList(convert);
        return orderReturnVO;
    }

    @Override
    @Transactional
    public void cancel(String edit, Long id) {
        OrderReturnDO oldDO = ValidateUtil.getOne(baseMapper, OrderReturnDO::getId, id, "售后单");
        AdminUserContext.compareCompany(oldDO.getCompanyId());

        // 更改原定单状态,更改售后订单状态
        OrderDO orderDo = orderManager.getById(oldDO.getOrderId());
        switch (edit) {
            case "end":
                orderDo.setStatus(SaleOrderStatusEnum.SALE_AFTER_END);
                oldDO.setStatus(ReturnOrderStatusEnum.SALE_AFTER_END);
                break;
            case "cancel":
                orderDo.setStatus(SaleOrderStatusEnum.SALE_AFTER_CANCEL);
                oldDO.setStatus(ReturnOrderStatusEnum.SALE_AFTER_CANCEL);
                break;
            default:
                throw new ServiceException("非法操作");
        }
        updateById(oldDO);
        orderManager.updateById(orderDo);
    }

    /**
     * 查询订单退货统计分页列表数据
     *
     * @param params 查询参数
     * @return
     */
    @Override
    public WebPage statistics(OrderReturnStatisticsQueryParam params) {
        IPage<OrderReturnStatistics> iPage = this.orderReturnMapper.selectOrderReturnPage(new Page(params.getPageNo(), params.getPageSize()), params);
        return PageConvert.convert(iPage);
    }

    /**
     * 导出订单退货统计列表数据
     *
     * @param response
     * @param params   查询参数
     */
    @Override
    public void export(HttpServletResponse response, OrderReturnStatisticsQueryParam params) {
        //查询库存报损单商品列表
        List<OrderReturnStatistics> list = this.orderReturnMapper.selectOrderReturnList(params);

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        for (OrderReturnStatistics statistics : list) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("所属分部", statistics.getDeptName());
            map.put("仓库名称", statistics.getWarehouseName());
            map.put("销售经理", statistics.getDistributionName());
            map.put("退货单编号", statistics.getSn());
            map.put("订单编号", statistics.getOrderSn());
            map.put("退货时间", DateUtil.toString(statistics.getReturnTime(), "yyyy-MM-dd HH:mm:ss"));
            map.put("入库单号", statistics.getWarehouseEntrySn());
            map.put("商品编号", statistics.getProductSn());
            map.put("商品名称", statistics.getProductName());
            map.put("商品类别", statistics.getCategoryName());
            map.put("规格型号", statistics.getProductSpecification());
            map.put("单位", statistics.getProductUnit());
            map.put("退货数量", statistics.getReturnNum());
            rows.add(map);
        }

        writer.write(rows, true);

        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=order_return.xlsx");
        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);
    }


    private Map<Long, OrderItemDO> checkOrderItem(OrderReturnDTO orderReturnDTO) {
        if (orderReturnDTO.getItemList().stream().anyMatch(orderReturnItemDTO -> orderReturnItemDTO.getOrderItemId() == null)) {
            throw new ServiceException("订单项id不能为空");
        }

        List<Long> orderItemIds = convertList(orderReturnDTO.getItemList(), OrderReturnItemDTO::getOrderItemId);
        List<OrderItemDO> orderItemList = orderItemManager.listByIds(orderItemIds);
        Map<Long, OrderItemDO> orderItemMap = convertMap(orderItemList, OrderItemDO::getId, Function.identity());
        for (OrderReturnItemDTO returnItemDTO : orderReturnDTO.getItemList()) {
            Long orderItemId = returnItemDTO.getOrderItemId();
            OrderItemDO orderItemDO = orderItemMap.get(orderItemId);
            if (orderItemDO == null) {
                throw ServiceException.format("订单项{}不存在", orderItemId);
            }
            if (!orderItemDO.getOrderId().equals(orderReturnDTO.getOrderId())) {
                throw ServiceException.format("订单项{}不属于当前订单", orderItemId);
            }
            if ((orderItemDO.getReturnNum() + returnItemDTO.getReturnNum()) > orderItemDO.getNum()) {
                throw ServiceException.format("商品【{}】可退货数量不足", orderItemDO.getProductName());
            }
        }

        return orderItemMap;
    }
}

