package com.yeejoin.amos.boot.module.hygf.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yeejoin.amos.boot.module.hygf.api.Enum.PreparationMoneyEnum;
import com.yeejoin.amos.boot.module.hygf.api.dto.PeasantHouseholdDto;
import com.yeejoin.amos.boot.module.hygf.api.dto.PreparationMoneyLogDto;
import com.yeejoin.amos.boot.module.hygf.api.dto.PreparationPageDto;
import com.yeejoin.amos.boot.module.hygf.api.entity.DocumentBom;
import com.yeejoin.amos.boot.module.hygf.api.entity.DocumentStation;
import com.yeejoin.amos.boot.module.hygf.api.entity.PeasantHousehold;
import com.yeejoin.amos.boot.module.hygf.api.entity.PreparationMoney;
import com.yeejoin.amos.boot.module.hygf.api.entity.PreparationMoneyLog;
import com.yeejoin.amos.boot.module.hygf.api.entity.UnitInfo;
import com.yeejoin.amos.boot.module.hygf.api.mapper.PreparationMoneyMapper;
import com.yeejoin.amos.boot.module.hygf.api.service.IPreparationMoneyService;
import com.yeejoin.amos.boot.module.hygf.api.dto.PreparationMoneyDto;
import com.yeejoin.amos.component.robot.AmosRequestContext;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.typroject.tyboot.core.foundation.exception.BaseException;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.rdbms.service.BaseService;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 发货单服务实现类
 *
 * @author system_generator
 * @date 2023-08-17
 */
@Service
public class PreparationMoneyServiceImpl extends BaseService<PreparationMoneyDto,PreparationMoney,PreparationMoneyMapper> implements IPreparationMoneyService {


    @Autowired
    private PreparationMoneyMapper preparationMoneyMapper;
    @Autowired
    private PowerStationServiceImpl powerStationService;
    @Autowired
    private PeasantHouseholdServiceImpl peasantHouseholdService;
    @Autowired
    private DocumentBomServiceImpl documentBomService;
    @Autowired
    private DocumentStationServiceImpl documentStationService;
    @Autowired
    private AmosRequestContext amosRequestContext;
    @Autowired
    private UnitInfoServiceImpl unitInfoService;
    @Autowired
    private PreparationMoneyLogServiceImpl preparationMoneyLogService;
    /**
     * 分页查询
     */
    public IPage<PreparationMoney> queryForPreparationMoneyPage(PreparationPageDto  dto)   {

        //列表数据组装
        QueryWrapper<PreparationMoney> qw = new QueryWrapper<>();
        qw.ge(StringUtils.isNotEmpty(dto.getStartDate()), "order_time", dto.getStartDate());
        qw.le(StringUtils.isNotEmpty(dto.getEndDate()), "order_time", dto.getEndDate());
        qw.eq(StringUtils.isNotEmpty(dto.getConsigneeAddress()), "consignee_address", dto.getConsigneeAddress());
        qw.eq(StringUtils.isNotEmpty(dto.getDealerId()), "dealer_id", dto.getDealerId());
        qw.like(StringUtils.isNotEmpty(dto.getOddNumbers()), "odd_numbers", dto.getOddNumbers());
        qw.like(StringUtils.isNotEmpty(dto.getSalesman()), "salesman", dto.getSalesman());
        qw.eq(StringUtils.isNotEmpty(dto.getDocumentState()), "document_state", dto.getDocumentState());
        qw.eq(StringUtils.isNotEmpty(dto.getShipmentStatus()), "shipment_status", dto.getShipmentStatus());
        qw.eq(StringUtils.isNotEmpty(dto.getReceivingStatus()), "receiving_status", dto.getReceivingStatus());
        if(dto.getIsdocumentStatezf()!=null&&dto.getIsdocumentStatezf()){
            qw.ne( "document_state", "已作废");
        }

        if (StringUtils.isNotEmpty(dto.getOrderBy())) {
            qw.orderBy(Boolean.TRUE, dto.getIsASC(), dto.getOrderBy());
        }else{
            qw.orderBy(Boolean.TRUE, Boolean.FALSE, "order_time");
        }
        IPage<PreparationMoney> warningQuestionInfoIPage = preparationMoneyMapper.selectPage(dto, qw);

        return warningQuestionInfoIPage;
    }

    /**
     * 列表查询 示例
     */
    public List<PreparationMoneyDto> queryForPreparationMoneyList()   {
        return this.queryForList("" , false);
    }

    /**
     * 获取发货单详情 by sequenceNbr
     *
     *
     * @param sequenceNbr sequenceNbr
     * @return {@link  PreparationMoneyDto}
     * @author Provence
     * @throws
     */
    public PreparationMoneyDto getObjectBySequenceNbr(Long sequenceNbr) {
        PreparationMoneyDto preparationMoneyDto = this.queryBySeq(sequenceNbr);
        // 加载BOM清单数据
        preparationMoneyDto.setDocumentBoms(documentBomService.listByPreparationMoneyId(sequenceNbr));
        // 加载发货电站数据
        List<Long> peasantHouseholdIds = documentStationService.list(new LambdaQueryWrapper<DocumentStation>()
                .select(DocumentStation::getStationId)
                .eq(DocumentStation::getPreparationMoneyId, sequenceNbr))
                .stream().map(DocumentStation::getStationId).collect(Collectors.toList());
        List<PeasantHousehold> peasantHouseholds = (List<PeasantHousehold>) peasantHouseholdService.listByIds(peasantHouseholdIds);
        preparationMoneyDto.setPowerStations(peasantHouseholds.stream().map(o -> entityToDto(o)).collect(Collectors.toList()));
        // 加载单据追踪数据
        List<PreparationMoneyLog> preparationMoneyLogDtos = preparationMoneyLogService.list(new LambdaQueryWrapper<PreparationMoneyLog>().eq(PreparationMoneyLog::getPreparationMoneyId, sequenceNbr));
        preparationMoneyDto.setPreparationMoneyLogs(preparationMoneyLogDtos.stream().map(o -> entityToDto(o)).collect(Collectors.toList()));
        return preparationMoneyDto;
    }

    private PeasantHouseholdDto entityToDto(PeasantHousehold o) {
        PeasantHouseholdDto dto = new PeasantHouseholdDto();
        BeanUtils.copyProperties(o, dto);
        return dto;
    }

    private PreparationMoneyLogDto entityToDto(PreparationMoneyLog o) {
        PreparationMoneyLogDto dto = new PreparationMoneyLogDto();
        BeanUtils.copyProperties(o, dto);
        return dto;
    }

    /**
     * 保存或更新发货单
     *
     *
     * @param model model
     * @return {@link  PreparationMoneyDto}
     * @author Provence
     * @throws
     */
    @Transactional
    @Override
    public PreparationMoneyDto saveOrUpdateObject(PreparationMoneyDto model) {
        boolean isUpdate = false;
        if (model.getSequenceNbr() != null) {
            // update
            PreparationMoney entity = this.getById(model);
            if (entity == null) {
                throw new RuntimeException("发货单不存在");
            }
            isUpdate = true;
        }
        // BOM 清单 后台查询数据库整合数据
        List<PeasantHouseholdDto> powerStations = model.getPowerStations();
        List<Long> powerHouseholdIds = powerStations.stream().map(PeasantHouseholdDto::getSequenceNbr).collect(Collectors.toList());
        // 后台组装BOM清单
        List<DocumentBom> documentBoms = documentBomService.assembleDocumentBom(powerHouseholdIds);
        if (CollectionUtils.isEmpty(documentBoms)) {
            // throw new BaseException("BOM清单为空", "400", "BOM清单为空");// 这里阻塞前端接口
            // 根据发货电站信息无法组装成BOM清单
            throw new RuntimeException("BOM清单为空");
        }
        // 根据BOM清单计算当前发货单的价格
        PreparationMoneyDto pmd = caculateShippingPrice(documentBoms);
        model.setInventoryPrice(pmd.getInventoryPrice());//清单价格
        model.setDiscount(pmd.getDiscount());//折扣
        model.setPromotion(pmd.getPromotion());//促销
        model.setTotalPrice(pmd.getTotalPrice());//总价
        // 前端传值改动太大, 从数据库获取dealerName
        String dealerName = Optional.ofNullable(unitInfoService.query().eq("amos_company_seq", model.getDealerId()).one()).map(UnitInfo::getName).orElse(null);
        model.setDealerName(dealerName);
        // model.setContractPrice(pmd.getContractPrice());//合同价格
        if (!isUpdate) {
            // 初始化状态
            model.setReceivingStatus(PreparationMoneyEnum.RECEIVING_STATUS.未到货.getName());
            model.setShipmentStatus(PreparationMoneyEnum.SHIPMENT_STATUS.未发货.getName());
            model.setDocumentState(PreparationMoneyEnum.DOCUMENT_STATE.未完成.getName());
        }
        PreparationMoney entity = new PreparationMoney();
        BeanUtils.copyProperties(model, entity);
        this.saveOrUpdate(entity);
        documentBoms.stream().forEach(d -> d.setPreparationMoneyId(entity.getSequenceNbr()));
        List<DocumentStation> documentStations = powerStations.stream().map(o -> buildDocumentStations(entity.getSequenceNbr(), o)).collect(Collectors.toList());
        if (isUpdate) {
            documentBomService.remove(new LambdaQueryWrapper<DocumentBom>().select(DocumentBom::getSequenceNbr).eq(DocumentBom::getPreparationMoneyId, entity.getSequenceNbr()));
            documentStationService.remove(new LambdaQueryWrapper<DocumentStation>().select(DocumentStation::getSequenceNbr).eq(DocumentStation::getPreparationMoneyId, entity.getSequenceNbr()));
        }
        documentBomService.saveOrUpdateBatch(documentBoms);
        documentStationService.saveOrUpdateBatch(documentStations);
        // 记录操作日志
        PreparationMoneyLog preparationMoneyLog = new PreparationMoneyLog();
        preparationMoneyLog.setPreparationMoneyId(entity.getSequenceNbr());
        preparationMoneyLog.setOperationContent(String.format("备货单保存【备货单号:%s】", entity.getOddNumbers()));
        preparationMoneyLogService.save(preparationMoneyLog);
        return model;
    }

    private DocumentStation buildDocumentStations(Long sequenceNbr, PeasantHouseholdDto dto) {
        String recUserId = amosRequestContext.getUserId();
        String recUserName = amosRequestContext.getUserName();
        DocumentStation documentStation = new DocumentStation();
        documentStation.setPreparationMoneyId(sequenceNbr);
        documentStation.setStationId(dto.getSequenceNbr());
        documentStation.setRecUserId(recUserId);
        documentStation.setRecUserName(recUserName);
        return documentStation;
    }

    /**
     * 更新发货单状态
     *
     *
     * @param sequenceNbr 发货单ID
     * @param operationType 操作类型(RECEIPT-确认收货, DELIVERY-发货, DISCARD-废弃)
     * @return {@link  Boolean}
     * @author Provence
     * @throws
     */
    @Override
    public Boolean updatePreparationMoneyStatus(Long sequenceNbr, String operationType) {
        PreparationMoney preparationMoney =  preparationMoneyMapper.selectById(sequenceNbr);
        if (preparationMoney ==  null) {
            throw new RuntimeException("订单不存在");
        }
        PreparationMoneyLog preparationMoneyLog = new PreparationMoneyLog();
        preparationMoneyLog.setPreparationMoneyId(preparationMoney.getSequenceNbr());
        switch (operationType) {
            case "RECEIPT":
                // 确认收货 -> 到货状态 -> 已到货 -> 订单状态改为 已完成
                if (!PreparationMoneyEnum.SHIPMENT_STATUS.已发货.getName().equals(preparationMoney.getShipmentStatus())) {
                    throw new RuntimeException("订单未发货, 无法确认收货");
                }
                preparationMoney.setReceivingStatus(PreparationMoneyEnum.RECEIVING_STATUS.已到货.getName());
                preparationMoney.setDocumentState(PreparationMoneyEnum.DOCUMENT_STATE.已完成.getName());
                preparationMoney.setDeliveryTime(new Date());
                preparationMoneyLog.setOperationContent(String.format("备货单确认收货【备货单号:%s】", preparationMoney.getOddNumbers()));
                break;
            case "DELIVERY":
                // 发货 -> 发货状态 -> 已发货
                preparationMoney.setShipmentStatus(PreparationMoneyEnum.SHIPMENT_STATUS.已发货.getName());
                preparationMoneyLog.setOperationContent(String.format("备货单发货【备货单号:%s】", preparationMoney.getOddNumbers()));
                break;
            case "DISCARD":
                // 作废
                // 订单状态 -> 已废弃
                if (PreparationMoneyEnum.RECEIVING_STATUS.已到货.getName().equals(preparationMoney.getReceivingStatus())) {
                    throw new RuntimeException("订单已到货, 无法作废");
                }
                preparationMoney.setDocumentState(PreparationMoneyEnum.DOCUMENT_STATE.作废.getName());
                preparationMoneyLog.setOperationContent(String.format("备货单作废【备货单号:%s】", preparationMoney.getOddNumbers()));
                break;
            default:
                break;
        }
        preparationMoneyLogService.save(preparationMoneyLog);
        return preparationMoneyMapper.updateById(preparationMoney) > 0;
    }

    /**
     * 根据前端选择的发货电站ID列表计算BOM清单价格
     *
     *
     * @param powerHouseholdIds 发货电站ID
     * @return {@link  PreparationMoneyDto}
     * @author Provence
     * @throws
     */
    public PreparationMoneyDto caculateShippingPriceByPowerHouseHoldIds(List<Long> powerHouseholdIds) {
        List<DocumentBom> documentBoms = documentBomService.assembleDocumentBom(powerHouseholdIds);
        return caculateShippingPrice(documentBoms);
    }

    /**
     * 根据前端选择的发货电站ID列表计算BOM清单价格
     *
     *
     * @param documentBoms BOM清单
     * @return {@link  PreparationMoneyDto}
     * @author Provence
     * @throws
     */
    public PreparationMoneyDto caculateShippingPrice(List<DocumentBom> documentBoms) {
        // 获取BOM清单数据
        // 单价 * 经销商折扣 * 促销 * 需求数量
        BigDecimal totalPrice = new BigDecimal(0);
        BigDecimal totaldemandNumber = new BigDecimal(0);
        for (DocumentBom documentBom : documentBoms) {
            BigDecimal unitPrice = new BigDecimal(documentBom.getUnitPrice() == null?0:documentBom.getUnitPrice());//单价
            BigDecimal demandNumber = new BigDecimal(documentBom.getDemandNumber());//需求数量
            totalPrice = totalPrice.add(unitPrice.multiply(demandNumber));
            totaldemandNumber = totaldemandNumber.add(demandNumber);
        }
        PreparationMoneyDto preparationMoneyDto = new PreparationMoneyDto();
        preparationMoneyDto.setInventoryPrice(totalPrice.divide(totaldemandNumber).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());//清单价格
        preparationMoneyDto.setDiscount(0D);//折扣
        preparationMoneyDto.setPromotion(0D);//促销
        preparationMoneyDto.setContractPrice(0D);//合同价格 == 确认
        preparationMoneyDto.setTotalPrice(totalPrice.doubleValue());
        return preparationMoneyDto;
    }
}