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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hys.app.framework.database.WebPage;
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.*;
import com.hys.app.mapper.erp.ChangeFormMapper;
import com.hys.app.model.base.rabbitmq.AmqpExchange;
import com.hys.app.model.erp.dos.ChangeForm;
import com.hys.app.model.erp.dos.ChangeFormProduct;
import com.hys.app.model.erp.dto.ChangeFormDTO;
import com.hys.app.model.erp.dto.ChangeFormQueryParam;
import com.hys.app.model.erp.dto.ChangeFormStatisticsQueryParam;
import com.hys.app.model.erp.dto.message.ChangeFormAuditPassMessage;
import com.hys.app.model.erp.enums.ChangeFormStatusEnum;
import com.hys.app.model.erp.enums.NoBusinessTypeEnum;
import com.hys.app.model.erp.vo.ChangeFormAllowable;
import com.hys.app.model.erp.vo.ChangeFormStatistics;
import com.hys.app.model.erp.vo.ChangeFormVO;
import com.hys.app.model.system.dos.AdminUser;
import com.hys.app.service.erp.ChangeFormManager;
import com.hys.app.service.erp.ChangeFormProductManager;
import com.hys.app.service.erp.NoGenerateManager;
import com.hys.app.service.system.AdminUserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 换货单业务接口实现
 * @author dmy
 * 2023-12-05
 */
@Service
public class ChangeFormManagerImpl extends ServiceImpl<ChangeFormMapper, ChangeForm> implements ChangeFormManager {

    @Autowired
    private NoGenerateManager noGenerateManager;

    @Autowired
    private ChangeFormProductManager changeFormProductManager;

    @Autowired
    private ChangeFormMapper changeFormMapper;

    @Autowired
    private MessageSender messageSender;

    @Autowired
    private AdminUserManager adminUserManager;

    /**
     * 查询换货单分页列表数据
     *
     * @param params 查询参数
     * @return
     */
    @Override
    public WebPage list(ChangeFormQueryParam params) {
        IPage<ChangeForm> iPage = this.lambdaQuery()
                .like(StringUtil.notEmpty(params.getSn()), ChangeForm::getSn, params.getSn())
                .like(StringUtil.notEmpty(params.getStaffName()), ChangeForm::getStaffName, params.getStaffName())
                .eq(StringUtil.notEmpty(params.getStatus()), ChangeForm::getStatus, params.getStatus())
                .eq(params.getDeptId() != null, ChangeForm::getDeptId, params.getDeptId())
                .gt(params.getStartTime() != null, ChangeForm::getChangeTime, params.getStartTime())
                .lt(params.getEndTime() != null, ChangeForm::getChangeTime, params.getEndTime())
                .orderByDesc(ChangeForm::getCreateTime)
                .page(new Page<>(params.getPageNo(), params.getPageSize()));

        for (ChangeForm record : iPage.getRecords()) {
            ChangeFormAllowable allowable = new ChangeFormAllowable(record);
            record.setAllowable(allowable);
        }
        return PageConvert.convert(iPage);
    }

    /**
     * 新增换货单
     *
     * @param changeFormDTO 换货单信息
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void add(ChangeFormDTO changeFormDTO) {
        //构建换货单信息
        ChangeForm changeForm = new ChangeForm();
        BeanUtil.copyProperties(changeFormDTO, changeForm);
        //生成换货单编号
        String sn = noGenerateManager.generate(NoBusinessTypeEnum.ChangeForm);
        changeForm.setSn(sn);
        //设置创建时间
        changeForm.setCreateTime(DateUtil.getDateline());
        //设置状态默认为新创建（未提交）
        changeForm.setStatus(ChangeFormStatusEnum.NEW.name());
        //入库
        this.save(changeForm);
        //获取主键ID
        Long id = changeForm.getId();
        //保存退货商品信息
        this.changeFormProductManager.saveProduct(id, changeFormDTO.getReturnList(), 0);
        //报错换货商品信息
        this.changeFormProductManager.saveProduct(id, changeFormDTO.getChangeList(), 1);
    }

    /**
     * 编辑换货单
     *
     * @param id 主键ID
     * @param changeFormDTO 换货单信息
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void edit(Long id, ChangeFormDTO changeFormDTO) {
        //获取换货单旧数据
        ChangeForm changeForm  = this.getById(id);
        if (!ChangeFormStatusEnum.NEW.name().equals(changeForm.getStatus())
                && !ChangeFormStatusEnum.REJECT.name().equals(changeForm.getStatus())) {
            throw new ServiceException("只有状态为未提交或审核驳回的换货单才可以进行编辑操作");
        }
        //复制修改后的数据
        BeanUtil.copyProperties(changeFormDTO, changeForm);
        //修改后的换货单状态默认为未提交
        changeForm.setStatus(ChangeFormStatusEnum.NEW.name());
        //修改换货单信息
        this.updateById(changeForm);
        //保存退货商品信息
        this.changeFormProductManager.saveProduct(id, changeFormDTO.getReturnList(), 0);
        //报错换货商品信息
        this.changeFormProductManager.saveProduct(id, changeFormDTO.getChangeList(), 1);
    }

    /**
     * 删除换货单
     *
     * @param ids 换货单主键ID集合
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete(List<Long> ids) {
        List<ChangeForm> forms = this.lambdaQuery()
                .in(ChangeForm::getId, ids)
                .list();
        if (forms == null || forms.size() == 0) {
            throw new ServiceException("要删除的换货单不存在");
        }
        //验证换货单状态是否可以删除
        for (ChangeForm form : forms) {
            if (!ChangeFormStatusEnum.NEW.name().equals(form.getStatus())
                    && !ChangeFormStatusEnum.REJECT.name().equals(form.getStatus())) {
                throw new ServiceException("只有状态为未提交或审核驳回的换货单才可进行删除操作");
            }
        }
        //批量删除换货单
        this.removeByIds(ids);
        //删除退货商品信息
        this.changeFormProductManager.deleteProduct(ids, 0);
        //删除换货商品信息
        this.changeFormProductManager.deleteProduct(ids, 1);
    }

    /**
     * 获取换货单详情
     *
     * @param id 主键ID
     * @return
     */
    @Override
    public ChangeFormVO getDetail(Long id) {
        //换货单详情信息
        ChangeFormVO changeFormVO = new ChangeFormVO();
        //获取换货单信息
        ChangeForm changeForm = this.getById(id);
        //复制信息
        BeanUtil.copyProperties(changeForm, changeFormVO);
        //获取退货商品信息
        List<ChangeFormProduct> returnList = this.changeFormProductManager.list(id, 0);
        changeFormVO.setReturnList(returnList);
        //获取换货商品信息
        List<ChangeFormProduct> changeList = this.changeFormProductManager.list(id, 1);
        changeFormVO.setChangeList(changeList);

        //获取退货商品总金额
        double returnAmount = returnList.stream().mapToDouble(ChangeFormProduct::getAmount).sum();
        //获取换货商品总金额
        double changeAmount = changeList.stream().mapToDouble(ChangeFormProduct::getAmount).sum();
        if (returnAmount == changeAmount) {
            changeFormVO.setCheckAmountSame(true);
            changeFormVO.setDiffAmount(0.00);
        } else {
            changeFormVO.setCheckAmountSame(false);
            if (returnAmount > changeAmount) {
                double diff = CurrencyUtil.sub(returnAmount, changeAmount);
                changeFormVO.setDiffAmount(diff);
                changeFormVO.setDiffAmountMessage("换货单商品金额不一致：退货金额比换货金额多" + diff);
            } else {
                double diff = CurrencyUtil.sub(changeAmount, returnAmount);
                changeFormVO.setDiffAmount(diff);
                changeFormVO.setDiffAmountMessage("换货单商品金额不一致：换货金额比退货金额多" + diff);
            }
        }
        return changeFormVO;
    }

    /**
     * 审核换货单
     *
     * @param ids 换货单ID集合
     * @param status 审核状态 PASS：审核通过，REJECT：审核驳回
     * @param rejectReason 驳回原因
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void audit(List<Long> ids, String status, String rejectReason) {
        List<ChangeForm> forms = this.lambdaQuery()
                .in(ChangeForm::getId, ids)
                .list();
        if (forms == null || forms.size() == 0) {
            throw new ServiceException("要审核的换货单不存在");
        }
        if (!ChangeFormStatusEnum.PASS.name().equals(status)
                && !ChangeFormStatusEnum.REJECT.name().equals(status)) {
            throw new ServiceException("审核状态不正确");
        }
        if (ChangeFormStatusEnum.REJECT.name().equals(status)) {
            if (StringUtil.isEmpty(rejectReason)) {
                throw new ServiceException("请填写审核驳回原因");
            }
            if (rejectReason.length() > 200) {
                throw new ServiceException("驳回原因不能超过200个字符");
            }
        }
        //循环审核换货单
        for (ChangeForm form : forms) {
            if (!ChangeFormStatusEnum.WAIT.name().equals(form.getStatus())) {
                throw new ServiceException("只有状态为待审核的换货单才可以进行审核操作");
            }
        }
        //获取当前登录管理员
        AdminUser adminUser = this.adminUserManager.getCurrUser();
        //修改换货单状态
        this.lambdaUpdate()
                .set(ChangeForm::getStatus, status)
                .set(StringUtil.notEmpty(rejectReason), ChangeForm::getRejectReason, rejectReason)
                .set(ChangeForm::getAuditTime, DateUtil.getDateline())
                .set(ChangeForm::getAuditPersonId, adminUser.getId())
                .set(ChangeForm::getAuditPersonName, adminUser.getRealName())
                .in(ChangeForm::getId, ids)
                .update();

        //审核通过后需要对换货单产品进行入库和出库操作
        if (ChangeFormStatusEnum.PASS.name().equals(status)) {
            for (ChangeForm form : forms) {
                //todo 审核通过后需要对换货单产品进行入库和出库操作
                this.changeFormProductManager.updateProductStock(form.getId(), form.getWarehouseId());
            }

            // 发送审核通过消息
            ChangeFormAuditPassMessage message = new ChangeFormAuditPassMessage();
            message.setList(forms);
            this.messageSender.send(new MqMessage(AmqpExchange.CHANGE_FORM_AUDIT_PASS, AmqpExchange.CHANGE_FORM_AUDIT_PASS + "_ROUTING", message));

        }
    }

    /**
     * 换货单提交审核
     *
     * @param ids 换货单ID集合
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void submit(List<Long> ids) {
        List<ChangeForm> forms = this.lambdaQuery()
                .in(ChangeForm::getId, ids)
                .list();
        if (forms == null || forms.size() == 0) {
            throw new ServiceException("要提交审核的换货单不存在");
        }
        //循环验证换货单是否可以提交审核
        for (ChangeForm form : forms) {
            if (!ChangeFormStatusEnum.NEW.name().equals(form.getStatus())) {
                throw new ServiceException("只有状态为未提交的换货单才可以进行提交审核操作");
            }
        }
        //修改换货单状态为已提交（待审核）
        this.lambdaUpdate()
                .set(ChangeForm::getStatus, ChangeFormStatusEnum.WAIT.name())
                .set(ChangeForm::getSubmitTime, DateUtil.getDateline())
                .in(ChangeForm::getId, ids)
                .update();
    }

    /**
     * 换货单撤销提交审核
     *
     * @param ids 换货单ID集合
     */
    @Override
    @Transactional(value = "goodsTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void cancel(List<Long> ids) {
        List<ChangeForm> forms = this.lambdaQuery()
                .in(ChangeForm::getId, ids)
                .list();
        if (forms == null || forms.size() == 0) {
            throw new ServiceException("要撤销提交审核的换货单不存在");
        }
        //循环验证换货单是否可以撤销提交审核
        for (ChangeForm form : forms) {
            if (!ChangeFormStatusEnum.WAIT.name().equals(form.getStatus())) {
                throw new ServiceException("只有状态为已提交的换货单才可以进行撤销操作");
            }
        }
        //修改换货单状态为新创建（待提交）
        this.lambdaUpdate()
                .set(ChangeForm::getStatus, ChangeFormStatusEnum.NEW.name())
                .in(ChangeForm::getId, ids)
                .update();
    }

    /**
     * 查询商品换货单商品统计分页列表数据
     *
     * @param params 查询参数
     * @return
     */
    @Override
    public WebPage statistics(ChangeFormStatisticsQueryParam params) {
        IPage<ChangeFormStatistics> iPage = this.changeFormMapper.selectFormPage(new Page(params.getPageNo(), params.getPageSize()), params);
        return PageConvert.convert(iPage);
    }

    /**
     * 导出商品换货单商品列表
     *
     * @param response
     * @param params
     */
    @Override
    public void export(HttpServletResponse response, ChangeFormStatisticsQueryParam params) {
        //查询换货单商品列表
        List<ChangeFormStatistics> list = this.changeFormMapper.selectFormList(params);

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        for (ChangeFormStatistics statistics : list) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("换货单号", statistics.getSn());
            map.put("入库单号", statistics.getStockSn());
            map.put("换货时间", DateUtil.toString(statistics.getChangeTime(), "yyyy-MM-dd HH:mm:ss"));
            map.put("商品编号", statistics.getProductSn());
            map.put("商品名称", statistics.getProductName());
            map.put("商品类别", statistics.getCategoryName());
            map.put("规格型号", statistics.getSpecification());
            map.put("单位", statistics.getUnit());
            map.put("调换类型", statistics.getType() == 0 ? "退货" : "换货");
            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=change_form.xlsx");
        writer.flush(out, true);
        writer.close();
        IoUtil.close(out);
    }
}
