package com.gree.mall.manager.logic.material.manage;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ReUtil;
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.manager.bean.admin.AdminUserCom;
import com.gree.mall.manager.bean.material.manage.WebsitPartsOldOutRecordDTO;
import com.gree.mall.manager.bean.material.manage.WebsitPartsOldOutVO;
import com.gree.mall.manager.bean.material.manage.WebsitStockOutListBean;
import com.gree.mall.manager.commonmapper.MaterialMapper;
import com.gree.mall.manager.enums.IsEnum;
import com.gree.mall.manager.enums.material.NormTypeEnum;
import com.gree.mall.manager.enums.material.PartsObjectTypeEnum;
import com.gree.mall.manager.enums.material.WebsitGoodsTypeEnum;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.logic.common.CommonLogic;
import com.gree.mall.manager.plus.entity.AdminWebsit;
import com.gree.mall.manager.plus.entity.Storage;
import com.gree.mall.manager.plus.entity.WebsitGoods;
import com.gree.mall.manager.plus.entity.WebsitPartsOldOutRecord;
import com.gree.mall.manager.plus.service.*;
import com.gree.mall.manager.utils.ValidateUtil;
import com.gree.mall.manager.zfire.bean.PartsParamBean;
import com.gree.mall.manager.zfire.util.FieldUtils;
import lombok.RequiredArgsConstructor;
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 java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class WebsitPartsOldOutLogic {

    private final CommonLogic commonLogic;
    private final MaterialMapper materialMapper;
    private final WebsitPartsOldOutRecordService websitPartsOldOutRecordService;
    private final AdminWebsitService adminWebsitService;
    private final WebsitGoodsService websitGoodsService;
    private final WebitPartsOldStockLogic webitPartsOldStockLogic;
    private final StorageService storageService;
    private final WebsitPartsOldOutRecordBakService websitPartsOldOutRecordBakService;


    public IPage<WebsitPartsOldOutVO> pageList(PartsParamBean zfireParamBean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        FieldUtils.materialParam(zfireParamBean, WebsitPartsOldOutVO.class, adminUser);
        IPage<WebsitPartsOldOutVO> page = materialMapper.websitPartsOldOutPage(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()), zfireParamBean);
        return page;
    }

    public void add(List<WebsitStockOutListBean> beans) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        if (adminUser.getType() != 0) {
            throw new RuntimeException("非网点账号不能添加");
        }

        final List<AdminWebsit> websitList = adminWebsitService.lambdaQuery()
                .in(AdminWebsit::getWebsitId, adminUser.getAdminWebsitIds())
                .isNotNull(AdminWebsit::getPartsWebsitId)
                .list();

        Map<String, AdminWebsit> websitMap = websitList.stream()
                .collect(Collectors.toMap(AdminWebsit::getPartsWebsitId, Function.identity()));

        final List<Storage> storageList = storageService.lambdaQuery()
                .eq(Storage::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .in(Storage::getWebsitId, adminUser.getAdminWebsitIds())
                .eq(Storage::getIsDefault, IsEnum.Y.getValue())
                .list();

        Map<String, Storage> storageMap = storageList.stream()
                .collect(Collectors.toMap(Storage::getWebsitId, Function.identity()));

        if (CollectionUtil.isNotEmpty(beans)) {
            List<WebsitPartsOldOutRecord> recordList = new ArrayList<>();
            for (WebsitStockOutListBean bean : beans) {
                ValidateUtil.validate(bean);
                final AdminWebsit websit = websitMap.get(bean.getSendWebsitId());
                final Storage storage = storageMap.get(websit.getWebsitId());

                WebsitPartsOldOutRecord record = new WebsitPartsOldOutRecord();
                record.setId(IdWorker.getIdStr())
                        .setCompanyWechatId(adminUser.getAdminCompanyWechat().getCompanyWechatId())
                        .setCompanyWechatName(adminUser.getAdminCompanyWechat().getCompanyName())
                        .setId(IdWorker.getIdStr())
                        .setSysNo(record.getId())
                        .setVoucherNo(bean.getVoucherNo())
                        .setApplyNo(bean.getApplyNo())
                        .setRemark(bean.getRemark())
                        .setObjectType(bean.getObjectType())
                        .setPartsNumber(bean.getPartsNumber())
                        .setPartsName(bean.getPartsName())
                        .setMaterialGroupName(bean.getMaterialGroupName())
                        .setGoodsStockUnit(bean.getGoodsStockUnit())
                        .setQty(bean.getQty())
                        .setSendWebsitId(websit.getWebsitId())
                        .setSendWebsitName(websit.getName())
                        .setSendPartsWebsitId(websit.getPartsWebsitId())
                        .setOrderDate(DateUtil.date())
                        .setStorageId(storage.getStorageId())
                        .setStorageName(storage.getStorageName());
                recordList.add(record);
            }
            websitPartsOldOutRecordService.saveBatch(recordList);
        }
    }

    @Transactional
    public void importOldOut(List<Object> objects) {
        if (objects.size() > 0) {
            // 注入对象
            List<WebsitPartsOldOutRecordDTO> oldOutRecordDTOList = this.handleOldOutRecordObj(objects);
            for (int i = 0; i < oldOutRecordDTOList.size(); i++) {
                WebsitPartsOldOutRecordDTO oldOutRecord = oldOutRecordDTOList.get(i);
                Integer count = websitPartsOldOutRecordService.lambdaQuery()
                        .eq(WebsitPartsOldOutRecord::getSysNo, oldOutRecord.getSysNo())
                        .count();
                if (count > 0) {
                    // 已经处理过的系统序号就跳过
                    continue;
                }
                try {
                    webitPartsOldStockLogic.oldOutStock(oldOutRecord, websitPartsOldOutRecordService, true);
                } catch (Exception e) {
                    throw new RemoteServiceException("第" + (i+2) + "行，“" + oldOutRecord.getVoucherNo() + "”处理库存时出错，原因：" + e.getMessage());
                }
            }
        }
    }

    private List<WebsitPartsOldOutRecordDTO> handleOldOutRecordObj(List<Object> objects) {
        DateTime curDate = DateUtil.date();
        AdminUserCom adminUser = commonLogic.getAdminUser();

        if (adminUser.getType() == 2) {
            throw new RemoteServiceException("平台账号禁止操作");
        }

        final List<AdminWebsit> websitList = adminWebsitService.lambdaQuery()
                .in(AdminWebsit::getWebsitId, adminUser.getAdminWebsitIds())
                .isNotNull(AdminWebsit::getPartsWebsitId)
                .list();

        Map<String, AdminWebsit> websitMap = websitList.stream()
                .collect(Collectors.toMap(AdminWebsit::getPartsWebsitId, Function.identity()));

        // 查询配件资料
        final List<WebsitGoods> partsList = websitGoodsService.lambdaQuery()
                .in(WebsitGoods::getGoodsCode, objects.stream()
                        .map(v -> (Optional.ofNullable(((List<Object>) v).get(4))).orElse(""))
                        .collect(Collectors.toSet()))
                .eq(WebsitGoods::getGoodsType, WebsitGoodsTypeEnum.P.getKey())
                .eq(WebsitGoods::getNormType, NormTypeEnum.M.getKey())
                .list();

        Map<String, WebsitGoods> partsMap = partsList.stream()
                .collect(Collectors.toMap(WebsitGoods::getGoodsCode, Function.identity()));

        final List<Storage> storageList = storageService.lambdaQuery()
                .eq(Storage::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .in(Storage::getWebsitId, adminUser.getAdminWebsitIds())
                .eq(Storage::getIsDefault, IsEnum.Y.getValue())
                .list();

        Map<String, Storage> storageMap = storageList.stream()
                .collect(Collectors.toMap(Storage::getWebsitId, Function.identity()));

        List<WebsitPartsOldOutRecordDTO> oldOutRecordDTOS = new ArrayList<>();
        for (int i = 1; i < objects.size(); i++) {
            List<Object> row = (List<Object>) objects.get(i);
            String voucherNo = (String) row.get(0);
            String applyNo = (String) row.get(1);
            String remark = (String) row.get(2);
            String objectType = (String) row.get(3);
            String partsNumber = (String) row.get(4);
            String priceStr = (String) row.get(7);
            String qtyStr = (String) row.get(8);
            String newNo = (String) row.get(9);
            String primaryPriceStr = (String) row.get(10);
            String discPriceStr = (String) row.get(11);
            String realPriceStr = (String) row.get(12);
            String diffPriceStr = (String) row.get(13);
            String sendUnit = (String) row.get(14);
            String receiveUnit = (String) row.get(15);
            String orderDateStr = (String) row.get(16);
            String sysNo = (String) row.get(17);
            String receiveDate = (String) row.get(18);
            String operateBy = (String) row.get(19);
            String sendUnitArea = (String) row.get(20);
            String receiveUnitArea = (String) row.get(21);
            String repairCustomNo = (String) row.get(22);
            PartsObjectTypeEnum objectTypeEnum = PartsObjectTypeEnum.findDescByKey(objectType);
            if (StringUtils.isBlank(objectType) || Objects.isNull(objectTypeEnum)) {
                throw new RemoteServiceException("第" + (i+2) + "行，事物类型格式不符，只能是“退旧件,无件返回,新件退库”");
            }
            if (StringUtils.isBlank(voucherNo)) {
                throw new RemoteServiceException("第" + (i+2) + "行，凭证号不能为空");
            }
            if (StringUtils.isBlank(partsNumber)) {
                throw new RemoteServiceException("第" + (i+2) + "行，配件编码不能为空");
            }
            if (StringUtils.isBlank(sendUnit) || sendUnit.indexOf(":") <= 0) {
                throw new RemoteServiceException("第" + (i+2) + "行，发出单位格式不符");
            }
            if (StringUtils.isBlank(orderDateStr) || !ReUtil.isMatch("^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{1,2}:\\d{1,2}:\\d{1,2}", orderDateStr)) {
                throw new RemoteServiceException("第" + (i+1) + "行，开单日期格式不符，正确格式：yyyy-MM-dd HH:mm:ss");
            }
            String sendUnitNumber = sendUnit.split(":")[0];
            AdminWebsit sendShop = websitMap.get(sendUnitNumber);
            WebsitGoods parts = partsMap.get(partsNumber);
            if (Objects.isNull(sendShop)) {
                throw new RemoteServiceException("第" + (i+2) + "行，发出单位未配置");
            }
            if (Objects.isNull(parts)) {
                throw new RemoteServiceException("第" + (i+2) + "行，配件编码未配置");
            }
            if (StringUtils.isBlank(sysNo)) {
                throw new RemoteServiceException("第" + (i+2) + "行，系统序号不能为空");
            }
            final Storage storage = storageMap.get(sendShop.getWebsitId());

            WebsitPartsOldOutRecordDTO partsShopOldOutRecordDTO = new WebsitPartsOldOutRecordDTO();
            partsShopOldOutRecordDTO.setId(IdWorker.getIdStr())
                    .setCompanyWechatId(adminUser.getAdminCompanyWechat().getCompanyWechatId())
                    .setCompanyWechatName(adminUser.getAdminCompanyWechat().getCompanyName())
                    .setVoucherNo(voucherNo)
                    .setApplyNo(applyNo)
                    .setRemark(remark)
                    .setObjectType(objectType)
                    .setGoodsId(parts.getGoodsId())
                    .setPartsNumber(partsNumber)
                    .setPartsName(parts.getGoodsName())
                    .setMaterialGroupName(parts.getMaterialGroupName())
                    .setGoodsStockUnit(parts.getGoodsStockUnit())
                    .setPrice(new BigDecimal(StringUtils.isNotBlank(priceStr) ? priceStr : "0"))
                    .setQty(new BigDecimal(StringUtils.isNotBlank(qtyStr) ? qtyStr : "0"))
                    .setNewNo(newNo)
                    .setPrimaryPrice(new BigDecimal(StringUtils.isNotBlank(primaryPriceStr) ? primaryPriceStr : "0"))
                    .setDiscPrice(new BigDecimal(StringUtils.isNotBlank(discPriceStr) ? discPriceStr : "0"))
                    .setRealPrice(new BigDecimal(StringUtils.isNotBlank(realPriceStr) ? realPriceStr : "0"))
                    .setDiffPrice(new BigDecimal(StringUtils.isNotBlank(diffPriceStr) ? diffPriceStr : "0"))
                    .setSendUnit(sendUnit)
                    .setReceiveUnit(receiveUnit)
                    .setSendWebsitId(sendShop.getWebsitId())
                    .setSendWebsitName(sendShop.getName())
                    .setSendPartsWebsitId(sendShop.getPartsWebsitId())
                    .setReceiveWebsitId("")
                    .setReceiveWebsitName("")
                    .setReceivePartsWebsitId("")
                    .setOrderDate(StringUtils.isNotBlank(orderDateStr) ? DateUtil.parseDateTime(orderDateStr) : null)
                    .setSysNo(sysNo)
                    .setReceiveDate(StringUtils.isNotBlank(receiveDate) ? DateUtil.parseDate(receiveDate) : DateUtil.date())
                    .setOperateBy(operateBy)
                    .setSendUnitArea(sendUnitArea)
                    .setReceiveUnitArea(receiveUnitArea)
                    .setRepairCustomNo(repairCustomNo)
                    .setImportDate(curDate)
                    .setStorageId(storage.getStorageId())
                    .setStorageName(storage.getStorageName())
                    .setCreateBy(adminUser.getNickName())
                    .setCreateTime(curDate);
            partsShopOldOutRecordDTO.setAdminWebsit(sendShop);
            oldOutRecordDTOS.add(partsShopOldOutRecordDTO);
        }

        return oldOutRecordDTOS;
    }

    @Transactional
    public void confirm(List<String> ids) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        if (adminUser.getType() == 2) {
            throw new RuntimeException("网点账号不能审核");
        }
        List<WebsitPartsOldOutRecord> recordList = websitPartsOldOutRecordService.listByIds(ids);
        if (CollectionUtil.isNotEmpty(recordList)) {
            Date curDate = DateUtil.date();
            int i = 1;

            Map<String, AdminWebsit> websitMap = adminWebsitService.lambdaQuery()
                    .in(AdminWebsit::getWebsitId, recordList.stream().map(WebsitPartsOldOutRecord::getSendWebsitId).distinct().collect(Collectors.toList()))
                    .list()
                    .stream()
                    .collect(Collectors.toMap(AdminWebsit::getWebsitId, Function.identity()));

            for (WebsitPartsOldOutRecord partsShopOldOutRecord : recordList) {
                try {
                    WebsitPartsOldOutRecordDTO oldOutRecord = new WebsitPartsOldOutRecordDTO();
                    BeanUtils.copyProperties(partsShopOldOutRecord, oldOutRecord);
                    oldOutRecord.setReceiveDate(curDate);
                    oldOutRecord.setImportDate(curDate);
                    oldOutRecord.setOperateBy(adminUser.getNickName());
                    oldOutRecord.setAdminWebsit(websitMap.get(oldOutRecord.getSendWebsitId()));
                    webitPartsOldStockLogic.oldOutStock(oldOutRecord, websitPartsOldOutRecordService, false);
                } catch (Exception e) {
                    throw new RemoteServiceException("第" + (i) + "条，“" + partsShopOldOutRecord.getSysNo() + "”处理库存时出错，原因：" + e.getMessage());
                }
                i++;
            }
        }
    }

    @Transactional
    public void delOldOut(List<String> ids) throws Exception {
        if (CollectionUtil.isEmpty(ids)) {
            return;
        }
        List<WebsitPartsOldOutRecord> partsTransRecordList = websitPartsOldOutRecordService.lambdaQuery()
                .in(WebsitPartsOldOutRecord::getId, ids)
                .list();
        if (CollectionUtil.isEmpty(partsTransRecordList)) {
            return;
        }
        for (WebsitPartsOldOutRecord partsShopOldOutRecord : partsTransRecordList) {
            if (Objects.nonNull(partsShopOldOutRecord.getImportDate())) {
                webitPartsOldStockLogic.delOldOutStock(partsShopOldOutRecord);
            } else {
                partsShopOldOutRecord.deleteById();
            }
        }
    }
}
