package com.gree.mall.miniapp.logic.material.parts;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gree.mall.miniapp.bean.inf.ValidGroup;
import com.gree.mall.miniapp.bean.material.parts.*;
import com.gree.mall.miniapp.bean.material.stock.WorkerStockDTO;
import com.gree.mall.miniapp.bean.user.CurrentCompanyWechat;
import com.gree.mall.miniapp.commonmapper.MaterialMapper;
import com.gree.mall.miniapp.enums.PayTypeEnum;
import com.gree.mall.miniapp.enums.base.BaseEnum;
import com.gree.mall.miniapp.enums.material.*;
import com.gree.mall.miniapp.exception.RemoteServiceException;
import com.gree.mall.miniapp.logic.common.CommonLogic;
import com.gree.mall.miniapp.logic.material.stock.MaterialGoodsStockLogic;
import com.gree.mall.miniapp.plus.entity.*;
import com.gree.mall.miniapp.plus.service.*;
import com.gree.mall.miniapp.utils.ValidateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.ValidationException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OldRefundManageLogic {

    @Resource
    CommonLogic commonLogic;
    @Resource
    MaterialMapper materialMapper;
    @Resource
    WebsitPartsOldRefundManageService websitPartsOldRefundManageService;
    @Resource
    WebsitPartsOldRefundManageItemService websitPartsOldRefundManageItemService;
    @Resource
    WebsitPartsOldRefundManageRecordService websitPartsOldRefundManageRecordService;
    @Resource
    AdminWebsitService adminWebsitService;
    @Resource
    WorkerStockService workerStockService;
    @Resource
    WebsitGoodsService websitGoodsService;
    @Resource
    MaterialGoodsStockLogic materialGoodsStockLogic;
    @Resource
    WorkerSalesCustomerInfoService workerSalesCustomerInfoService;

    public IPage<OldRefundManageBean> appList(String applyNo, String repairFlag, String flag, String identity, String partsNumber, Integer pageNo, Integer pageSize) {
        CurrentCompanyWechat wechat = commonLogic.getCurrentCompanyWechat();
        IPage<OldRefundManageBean> page = materialMapper.appOldRefundList(new Page(pageNo, pageSize), wechat.getCompanyWechatId(), applyNo, repairFlag, flag, identity, partsNumber);
        return page;
    }

    public Object detail(String applyNo) {
        WebsitPartsOldRefundManage partsOldRefundManage = websitPartsOldRefundManageService.getById(applyNo);
        if (Objects.isNull(partsOldRefundManage)) {
            throw new RemoteServiceException("单据不存在");
        }
        List<WebsitPartsOldRefundManageItem> partsOldRefundManageItems = websitPartsOldRefundManageItemService.lambdaQuery()
                .eq(WebsitPartsOldRefundManageItem::getApplyNo, applyNo)
                .list();

        OldRefundManageBean oldRefundManageBean = new OldRefundManageBean();
        BeanUtils.copyProperties(partsOldRefundManage, oldRefundManageBean);
        if (Objects.nonNull(oldRefundManageBean.getApplyCategory()))
            oldRefundManageBean.setApplyCategoryName(BaseEnum.keyToEnumNotNull(PartsApplyCategoryEnum.class, oldRefundManageBean.getApplyCategory()).getRemark());
        if (Objects.nonNull(oldRefundManageBean.getApplyType()))
            oldRefundManageBean.setApplyType(BaseEnum.keyToEnumNotNull(PartsRefundApplyTypeEnum.class, oldRefundManageBean.getApplyType()).getRemark());
        if (Objects.nonNull(oldRefundManageBean.getRefundMode()))
            oldRefundManageBean.setRefundModeName(BaseEnum.keyToEnumNotNull(PartsRefundModeEnum.class, oldRefundManageBean.getRefundMode()).getRemark());

        oldRefundManageBean.setFlagName(BaseEnum.keyToEnumNotNull(PartsOrderFlagEnum.class, oldRefundManageBean.getFlag()).getRemark());
        // 单据状态是通过并且保内
        if (oldRefundManageBean.getFlag().equals(PartsOrderFlagEnum.AGREE.getKey()) &&
                oldRefundManageBean.getRepairFlag().equals(PartsRepairFlagEnum.INNER.getKey())) {
            oldRefundManageBean.setFlagName("待返还");
        }

        List<OldRefundManageItemBean> oldRefundManageItemBeanList = new ArrayList<>();
        for (WebsitPartsOldRefundManageItem partsOldRefundManageItem : partsOldRefundManageItems) {
            OldRefundManageItemBean oldRefundManageItemBean = new OldRefundManageItemBean();
            BeanUtils.copyProperties(partsOldRefundManageItem, oldRefundManageItemBean);

            oldRefundManageItemBeanList.add(oldRefundManageItemBean);
        }
        // 查询执行记录
        List<WebsitPartsOldRefundManageRecord> partsOldRefundManageRecords = websitPartsOldRefundManageRecordService.lambdaQuery()
                .eq(WebsitPartsOldRefundManageRecord::getApplyNo, partsOldRefundManage.getApplyNo())
                .list();

        List<OldRefundManageRecordBean> oldRefundManageRecordBeans = new ArrayList<>();
        for (WebsitPartsOldRefundManageRecord partsOldRefundManageRecord : partsOldRefundManageRecords) {
            OldRefundManageRecordBean oldRefundManageRecordBean = new OldRefundManageRecordBean();
            BeanUtils.copyProperties(partsOldRefundManageRecord, oldRefundManageRecordBean);
            if (Objects.nonNull(oldRefundManageRecordBean.getRefundState())) {
                oldRefundManageRecordBean.setRefundStateName(BaseEnum.keyToEnumNotNull(PartsRefundStateEnum.class, oldRefundManageRecordBean.getRefundState()).getRemark());
            }
            if (Objects.nonNull(oldRefundManageRecordBean.getRepairFlag())) {
                oldRefundManageRecordBean.setRepairFlagName(BaseEnum.keyToEnumNotNull(PartsRepairFlagEnum.class, oldRefundManageRecordBean.getRepairFlag()).getRemark());
            }
            oldRefundManageRecordBean.setIsBackupName(oldRefundManageRecordBean.getIsBackup() ? "是" : "否");
            oldRefundManageRecordBeans.add(oldRefundManageRecordBean);
        }
        oldRefundManageBean.setPartsOldRefundManageRecordList(oldRefundManageRecordBeans);

        oldRefundManageBean.setOldRefundManageItemBeanList(oldRefundManageItemBeanList);
        return oldRefundManageBean;
    }

    @Transactional
    public String add(SalesCustomerPartsBean bean) {
        try {
            ValidateUtil.validate(bean, ValidGroup.Add.class);
            for (SalesCustomerPartsItemBean itemBean : bean.getItems()) {
                try {
                    ValidateUtil.validate(itemBean, ValidGroup.Add.class);
                } catch (ValidationException e) {
                    throw new RemoteServiceException("明细出错原因：" + e.getMessage());
                }
            }
            // 查询接收网点
            AdminWebsit websit = adminWebsitService.lambdaQuery()
                    .eq(AdminWebsit::getCompanyWechatId, bean.getCompanyWechatId())
                    .eq(AdminWebsit::getWebsitId, bean.getReceiveWebsitId())
                    .eq(AdminWebsit::getPartsWebsitId, bean.getReceivePartsWebsitId())
                    .one();
            if (Objects.isNull(websit)) {
                throw new RemoteServiceException("接收网点不存在");
            }

            // 查询师傅在接收网点的新件库存
            List<WorkerStock> workerStockList = workerStockService.lambdaQuery()
                    .eq(WorkerStock::getCompanyWechatId, bean.getCompanyWechatId())
                    .eq(WorkerStock::getIdentity, bean.getIdentity())
                    .eq(WorkerStock::getWebsitId, bean.getReceiveWebsitId())
                    .eq(WorkerStock::getPartsWebsitId, bean.getReceivePartsWebsitId())
                    .in(WorkerStock::getGoodsId, bean.getItems().stream()
                            .map(SalesCustomerPartsItemBean::getPartsNumber)
                            .collect(Collectors.toList()))
                    .list();
            if (CollectionUtil.isEmpty(workerStockList)) {
                throw new RemoteServiceException("在“" + websit.getName() + "”未找到新件配件库存");
            }

            // 查询配件资料
            List<WebsitGoods> partsList = websitGoodsService.lambdaQuery()
                    .eq(WebsitGoods::getCompanyWechatId, bean.getCompanyWechatId())
                    .in(WebsitGoods::getGoodsCode, bean.getItems().stream()
                            .map(SalesCustomerPartsItemBean::getPartsNumber)
                            .collect(Collectors.toList()))
                    .list();

            // 检查明细归还的数量必须大于0并且少于等于库存数量
            Map<String, WorkerStock> workerStockMap = workerStockList.stream()
                    .collect(Collectors.toMap(WorkerStock::getGoodsId, Function.identity()));
            Map<String, WebsitGoods> partsMap = partsList.stream()
                    .collect(Collectors.toMap(WebsitGoods::getGoodsCode, Function.identity()));

            OldRefundManageBean oldRefundManageBean = this.convertBean(bean, websit, partsMap);

            for (OldRefundManageItemBean itemBean : oldRefundManageBean.getOldRefundManageItemBeanList()) {
                WorkerStock workerStock = workerStockMap.get(itemBean.getNewPartsNumber());
                if (Objects.isNull(workerStock)) {
                    throw new RemoteServiceException("“" + itemBean.getNewPartsName() + "”新配件未找到库存记录");
                }
                if (itemBean.getQty().compareTo(workerStock.getQty()) > 0) {
                    throw new RemoteServiceException("“" + workerStock.getGoodsName() + "”使用新件数量不能大于库存数量");
                }
                if (itemBean.getQty().compareTo(BigDecimal.ZERO) < 1) {
                    throw new RemoteServiceException("“" + workerStock.getGoodsName() + "”使用新件数量必须大于0");
                }
                workerStockMap.get(itemBean.getNewPartsNumber()).setQty(workerStock.getQty().subtract(itemBean.getQty()));
            }

            String sheetId = commonLogic.generateMaterialNo(bean.getCompanyWechatId(), "JH", PartsRefTypeEnum.OLD_REFUND.getKey(), 13);
            oldRefundManageBean.setApplyNo(sheetId);

            // 保存主表和明细
            WebsitPartsOldRefundManage partsOldRefundManage = new WebsitPartsOldRefundManage();
            BeanUtils.copyProperties(oldRefundManageBean, partsOldRefundManage);
            // workOrderNo与pgId是同值
            partsOldRefundManage.setPgId(oldRefundManageBean.getWorkOrderNo());

            List<WebsitPartsOldRefundManageItem> partsOldRefundManageItems = new ArrayList<>();
            for (OldRefundManageItemBean itemBean : oldRefundManageBean.getOldRefundManageItemBeanList()) {
                WebsitPartsOldRefundManageItem partsOldRefundManageItem = new WebsitPartsOldRefundManageItem();
                itemBean.setId(IdWorker.getIdStr());
                itemBean.setApplyNo(sheetId);
                BeanUtils.copyProperties(itemBean, partsOldRefundManageItem);
                partsOldRefundManageItem.setNewUnitName(itemBean.getNewGoodsStockUnit());
                partsOldRefundManageItems.add(partsOldRefundManageItem);
            }
            partsOldRefundManage.setCreateBy(partsOldRefundManage.getWorkerName())
                    .setUpdateBy(partsOldRefundManage.getWorkerName())
                    .insert();

            // 刷新创建人和更新人
            websitPartsOldRefundManageService.lambdaUpdate()
                    .set(WebsitPartsOldRefundManage::getCreateBy, partsOldRefundManage.getWorkerName())
                    .set(WebsitPartsOldRefundManage::getUpdateBy, partsOldRefundManage.getWorkerName())
                    .eq(WebsitPartsOldRefundManage::getApplyNo, sheetId)
                    .update();

            websitPartsOldRefundManageItemService.saveBatch(partsOldRefundManageItems);

            // 减去师傅新件库存 增加旧件库存
            String refType = PartsRepairFlagEnum.INNER.getKey().equals(partsOldRefundManage.getRepairFlag()) ?
                    PartsRefTypeEnum.OLD_REFUND.getRemark() :
                    PartsRefTypeEnum.OUTSIDE_TO_SALES.getRemark();
            List<WorkerStockDTO> workerStockDTOList = this.createWorkerStockDTO(partsOldRefundManage, partsOldRefundManageItems,
                    refType, PartsAttrEnum.NEW.getKey(), PartsAttrEnum.OLD.getKey());
            materialGoodsStockLogic.handleWorkerStock(workerStockDTOList);

            return sheetId;
        } catch (Exception e) {
            WorkerSalesCustomerInfo info = workerSalesCustomerInfoService.lambdaQuery()
                    .eq(WorkerSalesCustomerInfo::getCompanyWechatId, bean.getCompanyWechatId())
                    .eq(WorkerSalesCustomerInfo::getWorkOrderNo, bean.getWorkOrderNo())
                    .eq(WorkerSalesCustomerInfo::getRepairFlag, bean.getRepairFlag())
                    .one();

            if (Objects.isNull(info)) {
                info = new WorkerSalesCustomerInfo();
                info.setErr(e.getMessage())
                        .setSalesCustomerJson(JSONUtil.toJsonStr(bean))
                        .setIdentity(bean.getIdentity())
                        .setCompanyWechatId(bean.getCompanyWechatId())
                        .insert();
            } else {
                info.setErr(e.getMessage())
                        .updateById();
            }
        }
        return null;
    }

    private List<WorkerStockDTO> createWorkerStockDTO(WebsitPartsOldRefundManage partsOldRefundManage,
                                                      List<WebsitPartsOldRefundManageItem> partsOldRefundManageItems,
                                                      String refType, String partsAttr1,
                                                      String partsAttr2) {
        List<WorkerStockDTO> workerStockDTOList = new ArrayList<>();
        if (StringUtils.isNotBlank(partsAttr1)) {
            for (WebsitPartsOldRefundManageItem refundManageItem : partsOldRefundManageItems) {
                WorkerStockDTO workerStockDTO = new WorkerStockDTO();
                workerStockDTO.setCompanyWechatId(partsOldRefundManage.getCompanyWechatId());
                workerStockDTO.setCompanyWechatName(partsOldRefundManage.getCompanyWechatName());
                workerStockDTO.setIdentity(partsOldRefundManage.getIdentity());
                workerStockDTO.setWorkerId(partsOldRefundManage.getWorkerId());
                workerStockDTO.setWorkerName(partsOldRefundManage.getWorkerName());
                workerStockDTO.setWebsitId(partsOldRefundManage.getReceiveWebsitId());
                workerStockDTO.setWebsitName(partsOldRefundManage.getReceiveWebsitName());
                workerStockDTO.setPartsWebsitId(partsOldRefundManage.getReceivePartsWebsitId());
                workerStockDTO.setSdate(DateUtil.date());
                workerStockDTO.setGoodsType(WebsitGoodsTypeEnum.P.toString());
                workerStockDTO.setGoodsId(refundManageItem.getNewPartsNumber());
                workerStockDTO.setGoodsName(refundManageItem.getNewPartsName());
                workerStockDTO.setMaterialGroupName(refundManageItem.getNewMaterialGroupName());
                workerStockDTO.setGoodsStockUnit(refundManageItem.getNewUnitName());
                workerStockDTO.setPrice(BigDecimal.ZERO);
                workerStockDTO.setRef(partsOldRefundManage.getApplyNo());
                workerStockDTO.setRefType(refType);
                workerStockDTO.setPartsAttr(partsAttr1);
                workerStockDTO.setChangeQty(refundManageItem.getQty());
                workerStockDTO.setDirectFlag(DirectFlagEnum.SUB.getKey());
                workerStockDTO.setRemark(refundManageItem.getRemark());
                workerStockDTO.setWorkerOrderNo(partsOldRefundManage.getWorkOrderNo());
                workerStockDTO.setOperateBy(partsOldRefundManage.getWorkerName());
                workerStockDTO.setOperateTime(DateUtil.date());

                workerStockDTOList.add(workerStockDTO);
            }
        }
        if (StringUtils.isNotBlank(partsAttr2)) {
            for (WebsitPartsOldRefundManageItem refundManageItem : partsOldRefundManageItems) {
                WorkerStockDTO workerStockDTO = new WorkerStockDTO();
                workerStockDTO.setCompanyWechatId(partsOldRefundManage.getCompanyWechatId());
                workerStockDTO.setCompanyWechatName(partsOldRefundManage.getCompanyWechatName());
                workerStockDTO.setIdentity(partsOldRefundManage.getIdentity());
                workerStockDTO.setWorkerId(partsOldRefundManage.getWorkerId());
                workerStockDTO.setWorkerName(partsOldRefundManage.getWorkerName());
                workerStockDTO.setWebsitId(partsOldRefundManage.getReceiveWebsitId());
                workerStockDTO.setWebsitName(partsOldRefundManage.getReceiveWebsitName());
                workerStockDTO.setPartsWebsitId(partsOldRefundManage.getReceivePartsWebsitId());
                workerStockDTO.setSdate(DateUtil.date());
                workerStockDTO.setGoodsType(WebsitGoodsTypeEnum.P.toString());
                workerStockDTO.setGoodsId(refundManageItem.getNewPartsNumber());
                workerStockDTO.setGoodsName(refundManageItem.getNewPartsName());
                workerStockDTO.setMaterialGroupName(refundManageItem.getNewMaterialGroupName());
                workerStockDTO.setGoodsStockUnit(refundManageItem.getNewUnitName());
                workerStockDTO.setPrice(BigDecimal.ZERO);
                workerStockDTO.setRef(partsOldRefundManage.getApplyNo());
                workerStockDTO.setRefType(refType);
                workerStockDTO.setPartsAttr(partsAttr2);
                workerStockDTO.setChangeQty(refundManageItem.getQty());
                workerStockDTO.setDirectFlag(DirectFlagEnum.ADD.getKey());
                workerStockDTO.setRemark(refundManageItem.getRemark());
                workerStockDTO.setWorkerOrderNo(partsOldRefundManage.getWorkOrderNo());
                workerStockDTO.setOperateBy(partsOldRefundManage.getWorkerName());
                workerStockDTO.setOperateTime(DateUtil.date());

                workerStockDTOList.add(workerStockDTO);
            }
        }
        return workerStockDTOList;
    }

    private OldRefundManageBean convertBean(SalesCustomerPartsBean bean, AdminWebsit websit, Map<String, WebsitGoods> partsMap) {
        OldRefundManageBean oldRefundManageBean = new OldRefundManageBean();
        BeanUtils.copyProperties(bean, oldRefundManageBean);
        if (PartsRepairFlagEnum.INNER.getKey().equals(bean.getRepairFlag())) {
            oldRefundManageBean.setApplyType(PartsRefundApplyTypeEnum.OLD.getKey());
        } else {
            oldRefundManageBean.setApplyType(PartsRefundApplyTypeEnum.NOT.getKey());
        }
        oldRefundManageBean.setReceiveWebsitName(websit.getName());
        oldRefundManageBean.setWebsitAddress(websit.getAddress());
        oldRefundManageBean.setCreateBy(bean.getWorkerName());
        oldRefundManageBean.setCreateTime(DateUtil.date());
        oldRefundManageBean.setUpdateBy(bean.getWorkerName());
        oldRefundManageBean.setUpdateTime(DateUtil.date());
        oldRefundManageBean.setFlag(PartsOrderFlagEnum.SAVE.toString());

        List<OldRefundManageItemBean> oldRefundManageItemBeanList = new ArrayList<>();
        for (SalesCustomerPartsItemBean itemBean : bean.getItems()) {
            OldRefundManageItemBean oldRefundManageItemBean = new OldRefundManageItemBean();
            BeanUtils.copyProperties(itemBean, oldRefundManageItemBean);
            WebsitGoods parts = partsMap.get(itemBean.getPartsNumber());
            if (Objects.isNull(parts)) {
                throw new RemoteServiceException("“" + itemBean.getPartsNumber() + "”配件编码未找到资料记录");
            }
            oldRefundManageItemBean.setOldPartsNumber(itemBean.getOldPartsNumber());
            oldRefundManageItemBean.setOldPartsName(itemBean.getOldPartsName());
            oldRefundManageItemBean.setNewPartsNumber(parts.getGoodsCode());
            oldRefundManageItemBean.setNewPartsName(parts.getGoodsName());
            oldRefundManageItemBean.setNewMaterialGroupName(parts.getMaterialGroupName());
            oldRefundManageItemBean.setNewGoodsStockUnit(parts.getGoodsStockUnit());
            oldRefundManageItemBeanList.add(oldRefundManageItemBean);
        }
        oldRefundManageBean.setOldRefundManageItemBeanList(oldRefundManageItemBeanList);
        return oldRefundManageBean;
    }

    @Transactional
    public void websitSalesHandle(String applyNo) throws Exception {
        final WebsitPartsOldRefundManage manage = websitPartsOldRefundManageService.getById(applyNo);
        if (Objects.isNull(manage)) {
            return;
        }
        final List<WebsitPartsOldRefundManageItem> items = websitPartsOldRefundManageItemService.lambdaQuery()
                .eq(WebsitPartsOldRefundManageItem::getApplyNo, applyNo)
                .list();
        String refType = PartsRepairFlagEnum.INNER.getKey().equals(manage.getRepairFlag()) ?
                PartsRefTypeEnum.OLD_REFUND.getRemark() :
                PartsRefTypeEnum.OUTSIDE_TO_SALES.getRemark();
        // 查找销售单并处理
        List<PartsRefundRecordDTO> partsRefundRecordDTOList = materialGoodsStockLogic.handleOldRefundWebsitSales(manage.getReceiveWebsitId(),
                manage.getReceivePartsWebsitId(), manage.getIdentity(), manage, items, refType);
        List<WebsitPartsOldRefundManageRecord> partsOldRefundManageRecordList = new ArrayList<>();
        BigDecimal refundAmount = BigDecimal.ZERO;
        for (PartsRefundRecordDTO partsRefundRecordDTO : partsRefundRecordDTOList) {
            WebsitPartsOldRefundManageRecord refundManageRecord = new WebsitPartsOldRefundManageRecord();
            BeanUtils.copyProperties(partsRefundRecordDTO, refundManageRecord);
            if (refundManageRecord.getRefundAmountMode().equals(PayTypeEnum.CASH.getKey())) {
                refundManageRecord.setRefundState(PartsRefundStateEnum.OK.toString());
            }
            refundAmount = refundAmount.add(refundManageRecord.getRefundAmount());
            partsOldRefundManageRecordList.add(refundManageRecord);
        }

        // 更新旧件返还主表退款金额
        websitPartsOldRefundManageService.lambdaUpdate()
                .set(WebsitPartsOldRefundManage::getSettlementState, false)
                .set(WebsitPartsOldRefundManage::getRefundAmount, refundAmount)
                .eq(WebsitPartsOldRefundManage::getApplyNo, applyNo)
                .update();

        // 保存旧件返还销售明细记录
        websitPartsOldRefundManageRecordService.saveBatch(partsOldRefundManageRecordList);
    }
}
