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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
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.SupplierReturnConverter;
import com.hys.app.converter.erp.SupplierReturnItemConverter;
import com.hys.app.framework.database.WebPage;
import com.hys.app.framework.exception.ServiceException;
import com.hys.app.framework.database.mybatisplus.base.BaseServiceImpl;
import com.hys.app.framework.rabbitmq.MessageSender;
import com.hys.app.framework.rabbitmq.MqMessage;
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.SupplierReturnMapper;
import com.hys.app.model.base.rabbitmq.AmqpExchange;
import com.hys.app.model.erp.dos.SupplierReturnDO;
import com.hys.app.model.erp.dos.SupplierReturnItemDO;
import com.hys.app.model.erp.dos.WarehouseEntryBatchDO;
import com.hys.app.model.erp.dos.WarehouseEntryDO;
import com.hys.app.model.erp.dto.*;
import com.hys.app.model.erp.dto.message.SupplierReturnAuditPassMessage;
import com.hys.app.model.erp.enums.FinanceIncomeTypeEnum;
import com.hys.app.model.erp.enums.NoBusinessTypeEnum;
import com.hys.app.model.erp.enums.StockChangeSourceEnum;
import com.hys.app.model.erp.enums.SupplierReturnStatusEnum;
import com.hys.app.model.erp.vo.SupplierReturnAllowable;
import com.hys.app.model.erp.vo.SupplierReturnStatistics;
import com.hys.app.model.erp.vo.SupplierReturnVO;
import com.hys.app.model.system.dos.AdminUser;
import com.hys.app.service.erp.*;
import com.hys.app.service.system.AdminUserManager;
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.stream.Collectors;

/**
 * 供应商退货业务层实现
 *
 * @author 张崧
 * @since 2023-12-14 11:12:46
 */
@Service
public class SupplierReturnManagerImpl extends BaseServiceImpl<SupplierReturnMapper, SupplierReturnDO> implements SupplierReturnManager {

    @Autowired
    private SupplierReturnConverter converter;

    @Autowired
    private SupplierReturnItemConverter itemConverter;

    @Autowired
    private WarehouseEntryManager warehouseEntryManager;

    @Autowired
    private WarehouseEntryBatchManager warehouseEntryBatchManager;

    @Autowired
    private NoGenerateManager noGenerateManager;

    @Autowired
    private SupplierReturnItemManager supplierReturnItemManager;

    @Autowired
    private WarehouseEntryBatchManager batchManager;

    @Autowired
    private SupplierReturnMapper supplierReturnMapper;

    @Autowired
    private MessageSender messageSender;

    @Autowired
    private AdminUserManager adminUserManager;

    @Autowired
    private WarehouseEntryProductManager warehouseEntryProductManager;

    @Autowired
    private FinanceItemManager financeItemManager;

    @Override
    public WebPage<SupplierReturnVO> list(SupplierReturnQueryParams queryParams) {
        WebPage<SupplierReturnDO> webPage = baseMapper.selectPage(queryParams);

//        List<Long> deptIds = convertList(webPage.getData(), SupplierReturnDO::getDeptId);
//        Map<Long, String> deptNameMap = deptService.listAndConvertMap(deptIds, DeptDO::getId, DeptDO::getName);
//
//        List<Long> warehouseIds = convertList(webPage.getData(), SupplierReturnDO::getWarehouseId);
//        Map<Long, String> warehouseNameMap = warehouseManager.listAndConvertMap(warehouseIds, WarehouseDO::getId, WarehouseDO::getName);
//
//        List<Long> supplierIds = convertList(webPage.getData(), SupplierReturnDO::getSupplierId);
//        Map<Long, String> supplierNameMap = supplierManager.listAndConvertMap(supplierIds, SupplierDO::getId, SupplierDO::getCustomName);

        return converter.convert(webPage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SupplierReturnDTO supplierReturnDTO) {
        check(supplierReturnDTO);

        // 保存供应商退货单
        SupplierReturnDO supplierReturnDO = converter.combination(supplierReturnDTO);
        supplierReturnDO.setSn(noGenerateManager.generate(NoBusinessTypeEnum.SupplierReturn, supplierReturnDTO.getDeptId()));
        supplierReturnDO.setStatus(SupplierReturnStatusEnum.NotSubmit);
        save(supplierReturnDO);

        // 保存供应商退货单明细
        List<SupplierReturnItemDO> itemList = itemConverter.combination(supplierReturnDO, supplierReturnDTO.getItemList(), supplierReturnDTO.getBatchMap());
        supplierReturnItemManager.saveBatch(itemList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SupplierReturnDTO supplierReturnDTO) {
        SupplierReturnDO oldDO = getById(supplierReturnDTO.getId());
        if (!new SupplierReturnAllowable(oldDO).getEdit()) {
            throw new ServiceException("不能进行编辑操作");
        }

        check(supplierReturnDTO);

        // 保存供应商退货单
        SupplierReturnDO supplierReturnDO = converter.combination(supplierReturnDTO);
        updateById(supplierReturnDO);

        // 保存供应商退货单明细
        List<SupplierReturnItemDO> itemList = itemConverter.combination(supplierReturnDO, supplierReturnDTO.getItemList(), supplierReturnDTO.getBatchMap());
        supplierReturnItemManager.deleteBySupplierReturnId(Collections.singletonList(supplierReturnDTO.getId()));
        supplierReturnItemManager.saveBatch(itemList);
    }

    @Override
    public SupplierReturnVO getDetail(Long id) {
        SupplierReturnVO supplierReturnVO = converter.convert(getById(id));

        List<SupplierReturnItemDO> supplierReturnItemList = supplierReturnItemManager.listBySupplierReturnId(id);
        supplierReturnVO.setItemList(itemConverter.convert(supplierReturnItemList));

        return supplierReturnVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> ids) {
        List<SupplierReturnDO> supplierReturnList = listByIds(ids);
        for (SupplierReturnDO supplierReturnDO : supplierReturnList) {
            if (!new SupplierReturnAllowable(supplierReturnDO).getDelete()) {
                throw new ServiceException(supplierReturnDO.getSn() + "不允许进行删除操作");
            }
        }
        supplierReturnItemManager.deleteBySupplierReturnId(ids);
        removeBatchByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submit(Long id) {
        // 校验
        SupplierReturnDO oldDO = getById(id);
        if (!new SupplierReturnAllowable(oldDO).getSubmit()) {
            throw new ServiceException("不允许进行提交操作");
        }

        lambdaUpdate()
                .set(SupplierReturnDO::getStatus, SupplierReturnStatusEnum.Submit)
                .eq(SupplierReturnDO::getId, id)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void withdraw(Long id) {
        // 校验
        SupplierReturnDO oldDO = getById(id);
        if (!new SupplierReturnAllowable(oldDO).getWithdraw()) {
            throw new ServiceException("不允许进行撤销操作");
        }

        lambdaUpdate()
                .set(SupplierReturnDO::getStatus, SupplierReturnStatusEnum.NotSubmit)
                .eq(SupplierReturnDO::getId, id)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void audit(List<Long> ids, SupplierReturnStatusEnum status, String remark) {
        if (status != SupplierReturnStatusEnum.AuditPass && status != SupplierReturnStatusEnum.AuditReject) {
            throw new ServiceException("审核参数错误");
        }

        List<SupplierReturnDO> supplierReturnList = listByIds(ids);
        for (SupplierReturnDO supplierReturnDO : supplierReturnList) {
            // 校验
            if (!new SupplierReturnAllowable(supplierReturnDO).getAudit()) {
                throw new ServiceException(supplierReturnDO.getSn() + "不能进行审核操作");
            }
        }

        lambdaUpdate()
                // 如果是驳回,状态改为未提交状态
                .set(SupplierReturnDO::getStatus, status == SupplierReturnStatusEnum.AuditReject ? SupplierReturnStatusEnum.NotSubmit : status)
                .set(SupplierReturnDO::getAuditRemark, remark)
                .set(SupplierReturnDO::getAuditBy, adminUserManager.getCurrUserName())
                .in(SupplierReturnDO::getId, ids)
                .update();

        // 如果审核通过
        if (status == SupplierReturnStatusEnum.AuditPass) {
            for (SupplierReturnDO supplierReturnDO : supplierReturnList) {
                List<SupplierReturnItemDO> returnItemList = supplierReturnItemManager.listBySupplierReturnId(supplierReturnDO.getId());
                // 扣减批次库存
                List<StockUpdateDTO> stockUpdateList = converter.convertStockUpdateList(returnItemList);
                batchManager.updateStock(StockChangeSourceEnum.SUPPLIER_RETURN, supplierReturnDO.getSn(), stockUpdateList);
                // 记录入库单明细的已退货数量
                for (SupplierReturnItemDO supplierReturnItemDO : returnItemList) {
                    warehouseEntryProductManager.updateReturnNum(supplierReturnItemDO.getWarehouseEntryItemId(), supplierReturnItemDO.getReturnNum());
                }
                // 生成财务明细
                double totalPrice = CurrencyUtil.sum(returnItemList, itemDO -> CurrencyUtil.mul(itemDO.getProductPrice(), itemDO.getReturnNum()));
                financeItemManager.addIncome(FinanceIncomeTypeEnum.SupplierReturn, supplierReturnDO.getSn(), totalPrice);
            }

            // 需要发送审核通过消息
            SupplierReturnAuditPassMessage message = new SupplierReturnAuditPassMessage();
            message.setList(supplierReturnList);
            this.messageSender.send(new MqMessage(AmqpExchange.SUPPLIER_RETURN_AUDIT_PASS, AmqpExchange.SUPPLIER_RETURN_AUDIT_PASS + "_ROUTING", message));
        }
    }

    /**
     * 查询供应商退货统计分页列表数据
     *
     * @param params 查询参数
     * @return
     */
    @Override
    public WebPage statistics(SupplierReturnStatisticsParam params) {
        IPage<SupplierReturnStatistics> iPage = this.supplierReturnMapper.selectSupplierReturnPage(new Page(params.getPageNo(), params.getPageSize()), params);
        return PageConvert.convert(iPage);
    }

    /**
     * 导出供应商退货统计列表
     *
     * @param response
     * @param params   查询参数
     */
    @Override
    public void export(HttpServletResponse response, SupplierReturnStatisticsParam params) {
        //查询出库单商品列表
        List<SupplierReturnStatistics> list = this.supplierReturnMapper.selectSupplierReturnList(params);

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        for (SupplierReturnStatistics statistics : list) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("所属部门", statistics.getDeptName());
            map.put("仓库名称", statistics.getWarehouseName());
            map.put("供应商", statistics.getSupplierName());
            map.put("退货单编号", statistics.getSn());
            map.put("退货时间", DateUtil.toString(statistics.getReturnTime(), "yyyy-MM-dd HH:mm:ss"));
            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=supplier_return.xlsx");
        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);
    }

    private void check(SupplierReturnDTO supplierReturnDTO) {
        WarehouseEntryDO warehouseEntryDO = warehouseEntryManager.getById(supplierReturnDTO.getWarehouseEntryId());
        if (warehouseEntryDO == null) {
            throw new ServiceException("入库单不存在");
        }
        AdminUser handleBy = adminUserManager.getModel(supplierReturnDTO.getHandleById());
        if (handleBy == null) {
            throw new ServiceException("经手人不存在");
        }

        List<Long> batchIds = supplierReturnDTO.getItemList().stream().map(SupplierReturnItemDTO::getWarehouseEntryBatchId).collect(Collectors.toList());
        Map<Long, WarehouseEntryBatchDO> batchMap = warehouseEntryBatchManager.listAndConvertMap(batchIds, WarehouseEntryBatchDO::getId);

        for (SupplierReturnItemDTO itemDTO : supplierReturnDTO.getItemList()) {
            WarehouseEntryBatchDO batchDO = batchMap.get(itemDTO.getWarehouseEntryBatchId());
            if (batchDO == null) {
                throw new ServiceException("批次：" + itemDTO.getWarehouseEntryBatchId() + "不存在");
            }
            if (!batchDO.getWarehouseEntryId().equals(warehouseEntryDO.getId())) {
                throw new ServiceException("批次：" + batchDO.getSn() + "不属于该入库单");
            }
            if (batchDO.getRemainNum() < itemDTO.getReturnNum()) {
                throw new ServiceException("批次：" + batchDO.getSn() + "剩余库存不足");
            }
        }

        // 填充数据
        supplierReturnDTO.setWarehouseEntryDO(warehouseEntryDO);
        supplierReturnDTO.setBatchMap(batchMap);
        supplierReturnDTO.setHandleBy(handleBy);
    }

}

