package com.jwipc.tender.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jwipc.aggregation.ModelAggregationService;
import com.jwipc.constant.FlagConst;
import com.jwipc.exception.DaoException;
import com.jwipc.inquiry.client.PriceInfoClient;
import com.jwipc.inquiry.client.PurchaseApplyBillDetailClient;
import com.jwipc.inquiry.dto.HistoryPriceInfoDTO;
import com.jwipc.inquiry.dto.PriceInfoClientDTO;
import com.jwipc.inquiry.dto.PurchaseApplyBillDetailClientDTO;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.supplier.clent.dto.SupplierContactsDTO;
import com.jwipc.supplier.clent.dto.SupplierDTO;
import com.jwipc.supplier.client.SupplierClient;
import com.jwipc.sys.client.EmailSendClient;
import com.jwipc.sys.client.ExchangeRateClient;
import com.jwipc.sys.client.SequenceClient;
import com.jwipc.sys.client.UserPurchaseGroupClient;
import com.jwipc.sys.client.dto.EmailTmpSendDTO;
import com.jwipc.sys.util.FinancialShareUtil;
import com.jwipc.tender.constant.*;
import com.jwipc.tender.convert.*;
import com.jwipc.tender.dto.*;
import com.jwipc.tender.entity.*;
import com.jwipc.tender.logic.TenderLogic;
import com.jwipc.tender.model.po.TenderCostContractPO;
import com.jwipc.tender.model.po.TenderDetailByIdPO;
import com.jwipc.tender.model.po.TenderListPO;
import com.jwipc.tender.model.query.TenderQuery;
import com.jwipc.tender.service.*;
import com.jwipc.util.DateUtils;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p> </p>
 *
 * @author BOGON
 * @version 1.0
 * @since JDK 1.8
 */
@Service
@RequiredArgsConstructor
public class TenderLogicImpl implements TenderLogic {
    private final ITenderService tenderService;
    private final TenderConvert tenderConvert;
    private final ITenderSettingCompetitiveService tenderSettingCompetitiveService;
    private final TenderSettingCompetitiveConvert tenderSettingCompetitiveConvert;
    private final ITenderSettingSecurityDepositService tenderSettingSecurityDepositService;
    private final TenderSettingSecurityDepositConvert tenderSettingSecurityDepositConvert;
    private final ITenderRoundService tenderRoundService;
    private final TenderRoundConvert tenderRoundConvert;
    private final ITenderAttachmentService tenderAttachmentService;
    private final TenderAttachmentConvert tenderAttachmentConvert;
    private final ITenderBidService tenderBidService;
    private final ITenderBidDetailService tenderBidDetailService;
    private final TenderBidConvert tenderBidConvert;
    private final ITenderDetailService tenderDetailService;
    private final TenderDetailConvert tenderDetailConvert;
    private final ITenderDetailExtService tenderDetailExtService;
    private final TenderDetailExtConvert tenderDetailExtConvert;
    private final ITenderOpenUserService tenderOpenUserService;
    private final TenderOpenUserConvert tenderOpenUserConvert;
    private final SequenceClient sequenceClient;
    private final ModelAggregationService modelAggregationService;
    private final PurchaseApplyBillDetailClient purchaseApplyBillDetailClient;
    private final SupplierClient supplierClient;
    private final ExchangeRateClient exchangeRateClient;
    private final EmailSendClient emailSendClient;
    private final UserPurchaseGroupClient userPurchaseGroupClient;
    private final PriceInfoClient priceInfoClient;
    private final FinancialShareUtil financialShareUtil;

    @Autowired
    StringRedisTemplate redisTemplate;


    @Override
    public PageView getList(TenderQuery query) {
        final Page<TenderListPO> page = PageUtil.toPage(query);
        final Set<String> userPurchaseGroupCode = userPurchaseGroupClient.getUserPurchaseGroupCode(
                LoginUtil.getUserId());
        query.setUserPurchaseGroupCodes(userPurchaseGroupCode);
        List<TenderListPO> tenderListPOS = tenderService.findList(page, query);
        List<TenderListDTO> list = tenderConvert.pos2Dtos(tenderListPOS);
        //需要查询投标数据
        final Set<Long> tenderIds = list.stream().map(TenderListDTO::getId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(tenderIds)) {
            final List<TenderBid> tenderBids = tenderBidService.list(
                    new LambdaQueryWrapper<TenderBid>().in(TenderBid::getTenderId, tenderIds));
            final Map<Long, List<TenderBid>> tenderBidMap = tenderBids.stream().collect(Collectors.groupingBy(
                    TenderBid::getTenderId));
            list.forEach(tenderListDTO -> {
                final Long id = tenderListDTO.getId();
                final List<TenderBid> tenderBids1 = tenderBidMap.get(id);
                if (CollUtil.isNotEmpty(tenderBids1)) {
                    final long agreeCount = tenderBids1.stream()
                            .filter(a -> Objects.nonNull(a.getAgreeFlag()) && a.getAgreeFlag() == FlagConst.Y.getCode())
                            .count();
                    tenderListDTO.setAgreeCount(agreeCount);
                    final long bidedCount = tenderBids1.stream()
                            .filter(a -> Objects.nonNull(a.getStatus()) &&
                                    (a.getStatus() == BidStatus.BIDDED.getStatus() ||
                                            a.getStatus() == BidStatus.BARGAINING.getStatus()))
                            .count();
                    tenderListDTO.setBidedCount(bidedCount);
                    tenderListDTO.setTotal(tenderBids1.size());
                }
            });
        }

        return PageUtil.getPV(list, page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdate(TenderSaveDTO saveDTO) {
        //type:0:新增,1修改;2:复制,3:发布
        final TenderBaseDTO tenderDto = saveDTO.getTender();
        final Integer type = saveDTO.getType();
        Tender tender = tenderConvert.dto2Entity(tenderDto);
        final Tender db = tenderService.getById(tender.getId());
        if (Objects.nonNull(db) && (type == TenderOptType.UPDATE.getType()
                || type == TenderOptType.RELEASE.getType())) {
            //1修改 3:发布
            tender.setUpdateId(LoginUtil.getUserId());
            tender.setUpdateTime(LocalDateTime.now());
            delRef(tender.getId(), type);
            //如果是发布需要把状态改成待审批
            if (type == TenderOptType.RELEASE.getType()) {
                tender.setStatus(TenderStatus.APPROVALING.getStatus());
                tender.setApprovelStatus(TenderApprovalStatus.UNAPPROVED.getStatus());
            } else {
                //数据库是什么状态，就是什么状态， 2025-04-15 邓京术
                tender.setStatus(db.getStatus());
            }
        } else if (Objects.nonNull(db) && type == TenderOptType.COPY.getType()) {
            //2:复制
            //需要把招标单号按照规则生成
            tender.setId(null);
            tender.setCode(sequenceClient.createSequenceNo(SequenceConst.TENDER_CODE.getCode()));
            tender.setCreateId(LoginUtil.getUserId());
            tender.setCreateTime(LocalDateTime.now());
            //需要把所有数据的id都置空
        } else {
            //需要把招标单号按照规则生成
            tender.setCode(sequenceClient.createSequenceNo(SequenceConst.TENDER_CODE.getCode()));
            tender.setCreateId(LoginUtil.getUserId());
            tender.setCreateTime(LocalDateTime.now());
        }
        tenderService.saveOrUpdate(tender);
        final Long tenderId = tender.getId();
        //竞价设置
        final TenderSettingCompetitiveDTO competitive = saveDTO.getCompetitive();
        TenderSettingCompetitive settingCompetitive = tenderSettingCompetitiveConvert.dto2Entity(competitive);
        settingCompetitive.setId(tenderId);
        tenderSettingCompetitiveService.saveOrUpdate(settingCompetitive);
        //保证金设置
        final TenderSettingSecurityDepositDTO securityDepositDTO = saveDTO.getSecurityDeposit();
        if (securityDepositDTO.getSecurityDepositFlag() == 1) {
            TenderSettingSecurityDeposit securityDeposit = tenderSettingSecurityDepositConvert.dto2Entity(
                    securityDepositDTO);
            securityDeposit.setId(tenderId);
            tenderSettingSecurityDepositService.saveOrUpdate(securityDeposit);
        } else {
            tenderSettingSecurityDepositService.removeById(tenderId);
        }
        //轮次时间设置
        final TenderRoundDTO dtoRound = saveDTO.getRound();
        TenderRound tenderRound = tenderRoundConvert.dto2Entity(dtoRound);
        tenderRound.setTenderId(tenderId);
        tenderRoundService.saveOrUpdate(tenderRound);
        tender.setRoundId(tenderRound.getId());
        tenderService.updateById(tender);
        //附件保存
        final List<TenderAttachmentDTO> tenderAttachmentList = saveDTO.getTenderAttachmentList();
        List<TenderAttachment> tenderAttachment = tenderAttachmentConvert.dtos2Entities(tenderAttachmentList);
        for (TenderAttachment attachment : tenderAttachment) {
            attachment.setMasterId(tenderId);
            attachment.setId(null);
        }
        if (CollUtil.isNotEmpty(tenderAttachment)) {
            tenderAttachmentService.saveOrUpdateBatch(tenderAttachment);
        }

        //供应商数据保存
        final List<TenderSupplierDTO> bidSupplierDtos = saveDTO.getBidSupplierDtos();
        List<TenderBid> tenderBids = tenderBidConvert.dtos2Entities1(bidSupplierDtos);
        for (TenderBid tenderBid : tenderBids) {
            tenderBid.setTenderId(tenderId);
            //需要获取汇率
            final BigDecimal exchangeRate = exchangeRateClient.getExchangeRateDefault(tenderBid.getCurrency());
            tenderBid.setExchangeRate(exchangeRate);
            tenderBid.setId(null);
        }
        if (CollUtil.isNotEmpty(tenderBids)) {
            tenderBidService.saveBatch(tenderBids);
        }

        //招标明细
        final List<TenderDetailAllDTO> dtoTenderDetails = saveDTO.getTenderDetails();
        List<TenderDetail> tenderDetailList = Lists.newArrayList();
        List<TenderDetailExt> tenderDetailExts = Lists.newArrayList();
        BigDecimal totalDoorPrice = BigDecimal.ZERO;
        //新保存的
        List<Long> sourceRowIds = new ArrayList<>();
        int i = 1;
        for (TenderDetailAllDTO tenderDetailAllDTO : dtoTenderDetails) {
            TenderDetail tenderDetail1 = tenderDetailConvert.dto2Entity(tenderDetailAllDTO);
            //如果是物料号需要把物料名称放到短描述中
            if (StrUtil.isEmpty(tenderDetail1.getMaterialCode())) {
                tenderDetail1.setMaterialDesc(tenderDetail1.getMaterialName());
            }
            if (Objects.nonNull(tenderDetailAllDTO.getSourceRowId())) {
                sourceRowIds.add(tenderDetailAllDTO.getSourceRowId());
            }
            tenderDetail1.setTenderId(tenderId);
            tenderDetail1.setId(IdWorker.getId());
            if (Objects.nonNull(tenderDetail1.getDoorPrice())) {
                if (Objects.nonNull(tenderDetail1.getCount())) {
                    totalDoorPrice = totalDoorPrice.add(
                            tenderDetail1.getDoorPrice().multiply(tenderDetail1.getCount()));
                } else {
                    totalDoorPrice = totalDoorPrice.add(tenderDetail1.getDoorPrice());
                }
            }
            tenderDetail1.setRowNo(i * 10);
            tenderDetailList.add(tenderDetail1);
            TenderDetailExt tenderDetailExt = tenderDetailExtConvert.dto2Entity(tenderDetailAllDTO);
            tenderDetailExt.setId(tenderDetail1.getId());
            tenderDetailExts.add(tenderDetailExt);
            final String factoryCode = tenderDetail1.getFactoryCode();
            final String materialCode = tenderDetail1.getMaterialCode();
            if (StrUtil.isNotEmpty(materialCode)) {
                final HistoryPriceInfoDTO historyLowPrice = priceInfoClient.getHistoryLowPrice(materialCode,
                        factoryCode);
                if (Objects.nonNull(historyLowPrice)) {
                    tenderDetail1.setHistoryPrice(historyLowPrice.getTaxPrice());
                    tenderDetail1.setHistoryPriceId(historyLowPrice.getId());
                }
                final HistoryPriceInfoDTO lastBidPrice = priceInfoClient.getLastBidPrice(materialCode, factoryCode);
                if (Objects.nonNull(lastBidPrice)) {
                    tenderDetail1.setLastBidPrice(lastBidPrice.getTaxPrice());
                    tenderDetail1.setLastBidPriceId(lastBidPrice.getId());
                }
            }
            i++;
        }
        //修改采购申请单
        if ((Objects.isNull(tenderDto.getId()) || (tenderDto.getId().compareTo(0L) == 0)) &&
                CollectionUtil.isNotEmpty(sourceRowIds)) {
            purchaseApplyBillDetailClient.updatePurchaseAppliyBillDetailForTender(tender.getCode(), sourceRowIds);
        }
        if (CollUtil.isNotEmpty(tenderDetailList)) {
            tenderDetailService.saveBatch(tenderDetailList);
        }
        if (CollUtil.isNotEmpty(tenderDetailExts)) {
            tenderDetailExtService.saveBatch(tenderDetailExts);
        }
        //汇总门槛价
        tenderService.update(new LambdaUpdateWrapper<Tender>()
                .set(Tender::getTotalDoorPrice, totalDoorPrice)
                .eq(Tender::getId, tender.getId()));
        //开标人员
        final List<TenderOpenUserDTO> userRelations = saveDTO.getUserRelations();
        List<TenderOpenUser> tenderOpenUsers = tenderOpenUserConvert.dto2Entity(userRelations);
        for (TenderOpenUser tenderOpenUser : tenderOpenUsers) {
            tenderOpenUser.setTenderId(tenderId);
            tenderOpenUser.setId(null);
        }
        if (CollUtil.isNotEmpty(tenderOpenUsers)) {
            tenderOpenUserService.saveBatch(tenderOpenUsers);
        }

    }

    private void delRef(Long tenderId, Integer type) {
        /**
         *如果是修改，需要删除表数据
         * 1.t_tender_round 2.t_tender_bid, t_tender_detail t_tender_open_user
         */
        tenderRoundService.remove(
                new LambdaQueryWrapper<TenderRound>().eq(TenderRound::getTenderId, tenderId));
        tenderBidService.remove(
                new LambdaQueryWrapper<TenderBid>().eq(TenderBid::getTenderId, tenderId));
        //需要查询然后删除扩展表
        final List<TenderDetail> dbTenderDetails = tenderDetailService
                .list(new LambdaQueryWrapper<TenderDetail>().eq(TenderDetail::getTenderId, tenderId));
        final List<Long> detailIds = dbTenderDetails.stream().map(TenderDetail::getId).collect(Collectors.toList());
        tenderDetailService
                .remove(new LambdaQueryWrapper<TenderDetail>().eq(TenderDetail::getTenderId, tenderId));
        if (CollUtil.isNotEmpty(detailIds)) {
            tenderDetailExtService
                    .removeBatchByIds(detailIds);
        }
        tenderOpenUserService
                .remove(new LambdaQueryWrapper<TenderOpenUser>().eq(TenderOpenUser::getTenderId, tenderId));
        tenderAttachmentService
                .remove(new LambdaQueryWrapper<TenderAttachment>().eq(TenderAttachment::getMasterId,
                        tenderId));
        tenderSettingCompetitiveService
                .removeById(tenderId);
        tenderSettingSecurityDepositService
                .removeById(tenderId);

    }

    @Override
    public TenderSaveDTO getDetail(Long id) {
        TenderSaveDTO tenderSaveDTO = new TenderSaveDTO();
        Tender tender = tenderService.getById(id);
        TenderBaseDTO tenderBaseDTO = tenderConvert.entity2Dto(tender);
        tenderSaveDTO.setTender(tenderBaseDTO);
        //投标明细
        List<TenderDetailAllDTO> tenderDetailDTOS = tenderDetailService.list(
                        new LambdaQueryWrapper<TenderDetail>().eq(TenderDetail::getTenderId, id)).stream()
                .map(tenderDetailConvert::entity2Dto).collect(Collectors.toList());
        final List<Long> detailIds = tenderDetailDTOS.stream().map(tenderDetailDTO -> tenderDetailDTO.getId())
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(detailIds)) {
            final List<TenderDetailExt> tenderDetailExts = tenderDetailExtService.listByIds(detailIds);
            final Map<Long, TenderDetailExt> collect = tenderDetailExts.stream()
                    .collect(Collectors.toMap(TenderDetailExt::getId, tenderDetailExt -> tenderDetailExt));
            for (TenderDetailAllDTO tenderDetailDTO : tenderDetailDTOS) {
                //计算可采购数量
                if (null == tenderDetailDTO.getEnablePurchaseNum()) {
                    //采购单查询需求数量（采购总数量）
                    if (StringUtils.isNotEmpty(tenderDetailDTO.getPurchaseBillCode()) && StringUtils.isNotEmpty(tenderDetailDTO.getPurchaseBillItemCode())) {
                        PurchaseApplyBillDetailClientDTO purchaseApplyBillDetailClientDTO = purchaseApplyBillDetailClient.getByBillCodeAndItemCode(tenderDetailDTO.getPurchaseBillCode(),tenderDetailDTO.getPurchaseBillItemCode());
                        BigDecimal enablePurchaseNum = tenderDetailService.getPurchaseNumAmountByBillNoAndCode(tenderDetailDTO.getPurchaseBillCode(),tenderDetailDTO.getPurchaseBillItemCode(),tenderDetailDTO.getId());
                        if (Objects.nonNull(enablePurchaseNum)) {
                            tenderDetailDTO.setEnablePurchaseNum(purchaseApplyBillDetailClientDTO.getApprovalNumber().subtract(enablePurchaseNum));
                        } else {
                            tenderDetailDTO.setEnablePurchaseNum(purchaseApplyBillDetailClientDTO.getApprovalNumber());
                        }
                    }
                }

                final TenderDetailExt tenderDetailExt = collect.get(tenderDetailDTO.getId());
                if (Objects.nonNull(tenderDetailExt)) {
                    tenderDetailExtConvert.entity2Dto(tenderDetailExt, tenderDetailDTO);
                }
            }
        }
        tenderSaveDTO.setTenderDetails(tenderDetailDTOS);
        //供应商
        final List<TenderBid> list = tenderBidService.list(
                new LambdaQueryWrapper<TenderBid>().eq(TenderBid::getTenderId, id));

        final List<TenderSupplierDTO> tenderBidDTOS = tenderBidConvert.entities2Dtos1(list);
        modelAggregationService.processRelationAggregation(tenderBidDTOS);
        //需要查询一下供应商联系人信息
        List<String> contactsIds = Lists.newArrayList();
        for (TenderSupplierDTO tenderBidDTO : tenderBidDTOS) {
            final String contactsId = tenderBidDTO.getContactsId();
            final List<String> ids = StrUtil.split(contactsId, StrUtil.COMMA);
            contactsIds.addAll(ids);
        }
        //查询联系人信息
        final List<SupplierContactsDTO> contactList = supplierClient.getContactList(contactsIds);
        if (CollUtil.isNotEmpty(contactList)) {
            final Map<Long, SupplierContactsDTO> collect = contactList.stream()
                    .collect(Collectors.toMap(SupplierContactsDTO::getId, supplierContactsDTO -> supplierContactsDTO));
            for (TenderSupplierDTO tenderBidDTO : tenderBidDTOS) {
                final String contactsId = tenderBidDTO.getContactsId();
                final List<String> ids = StrUtil.split(contactsId, StrUtil.COMMA);
                List<String> contactNames = Lists.newArrayList();
                for (String s : ids) {
                    final SupplierContactsDTO contactsDTO = collect.get(Long.parseLong(s));
                    if (Objects.nonNull(contactsDTO)) {
                        contactNames.add(
                                StrUtil.format("{}:{}", contactsDTO.getContactsName(), contactsDTO.getEmail()));
                    }
                }
                tenderBidDTO.setContacts(contactNames.stream().collect(Collectors.joining(StrUtil.COMMA)));
            }
        }
        tenderSaveDTO.setBidSupplierDtos(tenderBidDTOS);
        //附件
        final List<TenderAttachment> tenderFiles = tenderAttachmentService.list(
                new LambdaQueryWrapper<TenderAttachment>().eq(TenderAttachment::getMasterId, id)
                        .in(TenderAttachment::getType,
                                TenderAttachmentType.getTenderFileTypes()));
        if (CollUtil.isNotEmpty(tenderFiles)) {
            final List<TenderAttachmentDTO> tenderAttachmentDTOS = tenderFiles.stream()
                    .map(tenderAttachmentConvert::entity2Dto).collect(Collectors.toList());
            modelAggregationService.processRelationAggregation(tenderAttachmentDTOS);
            tenderSaveDTO.setTenderAttachmentList(tenderAttachmentDTOS);
        }
        //保证金设置
        final TenderSettingSecurityDeposit tenderDepositSettingList = tenderSettingSecurityDepositService.getById(id);
        if (Objects.nonNull(tenderDepositSettingList)) {
            final TenderSettingSecurityDepositDTO tenderSettingSecurityDepositDTO =
                    tenderSettingSecurityDepositConvert.entity2Dto(
                            tenderDepositSettingList);
            tenderSettingSecurityDepositDTO.setSecurityDepositFlag(FlagConst.Y.getCode());
            tenderSaveDTO.setSecurityDeposit(tenderSettingSecurityDepositDTO);
        }

        //竞价设置
        final TenderSettingCompetitive competitive = tenderSettingCompetitiveService.getById(id);
        TenderSettingCompetitiveDTO settingCompetitiveDTO = tenderSettingCompetitiveConvert.entity2Dto(competitive);
        tenderSaveDTO.setCompetitive(settingCompetitiveDTO);
        //查询轮次
        final TenderRound tenderRound = tenderRoundService.getOne(
                new LambdaQueryWrapper<TenderRound>().eq(TenderRound::getTenderId, id));
        if (Objects.nonNull(tenderRound)) {
            final TenderRoundDTO tenderRoundDTO = tenderRoundConvert.entity2Dto(tenderRound);
            tenderSaveDTO.setRound(tenderRoundDTO);
        }

        //查询开标小组
        final List<TenderOpenUser> tenderOpenTime = tenderOpenUserService.list(
                new LambdaQueryWrapper<TenderOpenUser>().eq(TenderOpenUser::getTenderId, id));
        List<TenderOpenUserDTO> userDTOS = tenderOpenUserConvert.entities2Dtos(tenderOpenTime);
        modelAggregationService.processRelationAggregation(userDTOS);
        tenderSaveDTO.setUserRelations(userDTOS);
        return tenderSaveDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void remove(Long id) {
        final Tender tender = tenderService.getById(id);
        if (Objects.isNull(tender)) {
            throw new DaoException("该标的信息不存在");
        }
        if (tender.getStatus() != TenderStatus.NEW.getStatus()) {
            throw new DaoException("该标的信息已提交，不能删除");
        }
        tenderService.removeById(id);
        //需要更新采购申请为未转
        purchaseApplyBillDetailClient.cancelPurchaseAppliyBillDetailTender(tender.getCode());
        delRef(tender.getId(), null);
    }

    @Override
    public void toVoid(Long id) {
        final Tender tender = tenderService.getById(id);
        if (Objects.isNull(tender)) {
            throw new DaoException("该标的信息不存在");
        }
        tenderService.update(new LambdaUpdateWrapper<Tender>().eq(Tender::getId, id)
                .set(Tender::getStatus, TenderStatus.VOID.getStatus()));
        //需要把投标数据变成做饭
        tenderBidService.update(new LambdaUpdateWrapper<TenderBid>().eq(TenderBid::getTenderId, id)
                .set(TenderBid::getStatus, BidStatus.CANCELLED.getStatus()));
        //需要更新采购申请为未转
        purchaseApplyBillDetailClient.cancelPurchaseAppliyBillDetailTender(tender.getCode());
    }

    @Override
    public PageView bargainingStatus(Long id) {
        List<TenderBid> tenderBids = tenderBidDetailService.getBargainingStatus(id);
        //需要过滤如果状态是议价完成就不需要议价中的数据
        final List<TenderBid> okTenderBids = Lists.newArrayList();
        List<TenderBid> okTenderBids1 = tenderBids.stream()
                .filter(a -> a.getStatus().equals(BargainingStatus.BARGAIN_SUCCESS.getValue())).toList();
        okTenderBids.addAll(okTenderBids1);
        final Set<Long> okSupplierId = okTenderBids1.stream().map(tenderBid -> tenderBid.getSupplierId())
                .collect(Collectors.toSet());
        final List<TenderBid> notOkTenderBids = tenderBids.stream()
                .filter(a -> a.getStatus().equals(BargainingStatus.BARGAINING.getValue()))
                .filter(a -> !okSupplierId.contains(a.getSupplierId())).toList();
        okTenderBids.addAll(notOkTenderBids);
        final List<TenderBidBaseDTO> tenderBidBaseDTOS = tenderBidConvert.entities2Dtos(okTenderBids);
        modelAggregationService.processRelationAggregation(tenderBidBaseDTOS);
        return PageUtil.getPV(tenderBidBaseDTOS, tenderBidBaseDTOS.size());
    }

    @Override
    public List<TenderCostContractDTO> getTenderCostContractList(Long tenderId) {
        List<TenderCostContractPO> tenderCostContractList = tenderService.getTenderCostContractList(tenderId);
        return tenderConvert.costContractPOs2DTOs(tenderCostContractList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approval(Long id, String remark, Integer status) {
        final Tender tender = tenderService.getById(id);
        if (Objects.isNull(tender)) {
            throw new DaoException("该招标信息不存在");
        }
        if (tender.getStatus() != TenderStatus.APPROVALING.getStatus()) {
            throw new DaoException("该招标信息不是审批中");
        }
        tender.setStatus(status == 1 ? TenderStatus.RELEASE.getStatus() : TenderStatus.REJECT.getStatus());
        tender.setApprovelStatus(status == 1 ? TenderApprovalStatus.PASS.getStatus() : TenderStatus.REJECT.getStatus());
        tender.setApprovelRemark(remark);
        tender.setApproverId(LoginUtil.getUserId());
        tender.setApprovelTime(LocalDateTime.now());
        //如果通过，需要把供应商的投标状态改成待确认
        tenderService.updateById(tender);
        if (tender.getStatus() == TenderStatus.RELEASE.getStatus()) {
            final List<TenderBid> tenderBids = tenderBidService.list(
                    new LambdaQueryWrapper<TenderBid>().eq(TenderBid::getTenderId, id));
            for (TenderBid tenderBid : tenderBids) {
                tenderBid.setStatus(BidStatus.TO_BE_CONFIRMED.getStatus());
            }
            if (CollUtil.isNotEmpty(tenderBids)) {
                tenderBidService.updateBatchById(tenderBids);
            }
            //需要发送邮件
            sendReleaseEmail(tenderBids, tender);
        }
    }

    private void sendReleaseEmail(List<TenderBid> tenderBids, Tender tender) {
        final Set<Long> supplierIds = tenderBids.stream().map(TenderBid::getSupplierId).collect(Collectors.toSet());
        final List<SupplierDTO> supplierByIds = supplierClient.getSupplierByIds(supplierIds);
        final Map<Long, SupplierDTO> supplierCache = supplierByIds.stream()
                .collect(Collectors.toMap(SupplierDTO::getId, a -> a));
        for (TenderBid tenderBid : tenderBids) {
            final SupplierDTO supplierDTO = supplierCache.get(tenderBid.getSupplierId());
            final String contactsId = tenderBid.getContactsId();
            Map<String, Object> params = Maps.newHashMap();
            params.put("title", tender.getTitle());
            params.put("supplierName", supplierDTO.getSupplierName());
            params.put("publicDate", DateUtils.formatYYYYMMDDDash(LocalDate.now()));
            if (StrUtil.isNotEmpty(contactsId)) {
                final List<String> contactsIds = StrUtil.split(contactsId, StrUtil.COMMA);
                final List<SupplierContactsDTO> contactList = supplierClient.getContactList(contactsIds);
                //获取邮箱
                final Set<String> emails = contactList.stream().filter(a -> StrUtil.isNotEmpty(a.getEmail()))
                        .map(a -> a.getEmail()).collect(Collectors.toSet());
                final EmailTmpSendDTO emailTxtSingleSendDTO = new EmailTmpSendDTO();
                emailTxtSingleSendDTO.setTemplateCode("JW_POST_100");
                emailTxtSingleSendDTO.setParams(params);
                emailTxtSingleSendDTO.setReceiver(emails);
                emailTxtSingleSendDTO.setSender(LoginUtil.getUserId());
                emailSendClient.async(emailTxtSingleSendDTO);
            }
        }
    }

    @Override
    public String getAgreement(Long tenderId) {
        final Tender tender = tenderService.getById(tenderId);
        return tender.getAgreement();
    }

    @Override
    public UpdateTimeDTO getTimeDTO(Long id) {
        final Tender tender = tenderService.getById(id);
        final Long roundId = tender.getRoundId();
        final TenderRound round = tenderRoundService.getById(roundId);
        final TenderRoundDTO tenderRoundDTO = tenderRoundConvert.entity2Dto(round);
        final TenderSettingSecurityDeposit securityDeposit = tenderSettingSecurityDepositService.getById(id);
        UpdateTimeDTO updateTimeDTO = new UpdateTimeDTO();
        updateTimeDTO.setRound(tenderRoundDTO);
        if (Objects.nonNull(securityDeposit)) {
            final TenderSettingSecurityDepositDTO securityDepositDTO = tenderSettingSecurityDepositConvert.entity2Dto(
                    securityDeposit);
            updateTimeDTO.setSecurityDeposit(securityDepositDTO);
        }
        return updateTimeDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTime(UpdateTimeDTO updateTimeDTO) {
        final TenderRoundDTO dtoRound = updateTimeDTO.getRound();
        final TenderRound round = tenderRoundConvert.dto2Entity(dtoRound);
        tenderRoundService.updateById(round);
        final TenderSettingSecurityDepositDTO securityDeposit = updateTimeDTO.getSecurityDeposit();
        if (Objects.nonNull(securityDeposit.getId())) {
            final TenderSettingSecurityDeposit entity = tenderSettingSecurityDepositConvert.dto2Entity(securityDeposit);
            tenderSettingSecurityDepositService.updateById(entity);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void stop(Long id) {
        final Tender tender = tenderService.getById(id);
        if (Objects.isNull(tender)) {
            throw new DaoException("招标单不存在");
        }
        if (TenderStatus.RELEASE.getStatus() != tender.getStatus()) {
            throw new DaoException("招标单不是投标状态");
        }
        tender.setStatus(TenderStatus.EXPIRED.getStatus());
        tender.setUpdateTime(LocalDateTime.now());
        tender.setUpdateId(LoginUtil.getUserId());
        tenderService.updateById(tender);
    }

    @Override
    public PageView supplierProcess(Long id, Integer type) {
        // 转合同情况
        if (type == 2) {
            List<TenderBidBaseDTO> tenderBidDTOS = new ArrayList<>();
            List<TenderDetailByIdPO> tenderDetailByIdPOList = tenderService.getConvertedContractByTenderId(id);
            tenderDetailByIdPOList.forEach(contract -> {
                TenderBidBaseDTO tenderBidBaseDTO = new TenderBidBaseDTO();
                tenderBidBaseDTO.setSupplierId(Long.valueOf(contract.getSupplierId()));
                tenderBidBaseDTO.setSupplierCode(contract.getSupplierCode());
                tenderBidBaseDTO.setSupplierName(contract.getSupplierName());
                tenderBidBaseDTO.setContractCode(contract.getContractCode());
                if (StringUtils.isNotEmpty(contract.getContractId())) {
                    // 费用类合同
                    tenderBidBaseDTO.setContractUrl(financialShareUtil.getFinancialShareFormUrl("er_contractbill", contract.getContractId()));
                    tenderBidBaseDTO.setContractType("费用合同");
                } else {
                    // 资产类合同
                    tenderBidBaseDTO.setContractType("合同");
                }
                tenderBidDTOS.add(tenderBidBaseDTO);
            });
            return PageUtil.getPV(tenderBidDTOS, tenderBidDTOS.size());
        }
        final LambdaQueryWrapper<TenderBid> wrapper = new LambdaQueryWrapper<TenderBid>().eq(TenderBid::getTenderId,
                id);
        if (type == FlagConst.Y.getCode()) {
            //需要查询待报价
            wrapper.eq(TenderBid::getAgreeFlag, FlagConst.Y.getCode());
        }
        final List<TenderBid> tenderBids = tenderBidService.list(wrapper);
        //查询投标主表，查看这个招标单的状态
        final Tender tender = tenderService.getById(id);
        //定标主表 status = 9 已完成 status = 5 已定标 10
        List<TenderBid> filteredBids = null;
        if(tender.getStatus().intValue() != 9  && tender.getStatus() .intValue() != 5){
            //2025-03-03新增修改逻辑
            //思路：1.先把供应商需要进行报价的物料价格数据全部找出来
            //2.通过 taxPrice 含税单价来判断是否报价了，能否取到历史配价格的
            //3.动态的查询未报价的在系统里最新有效期的价格给它附上值
            //4.再进行一个排名的排序返回给前端
            //需要把排名为空的放置最后
            filteredBids = tenderBids.stream()
                    .filter(bid -> bid.getStatus() != null && bid.getStatus() != 3)
                    .collect(Collectors.toList());

            List<Long> ids = filteredBids.stream()
                    .map(TenderBid::getId) // 将每个TenderBid对象映射到其id
                    .collect(Collectors.toList()); // 收集到List中
            LambdaQueryWrapper<TenderBidDetail> eq = new LambdaQueryWrapper<TenderBidDetail>().eq(TenderBidDetail::getTenderId, id);
            if(CollectionUtils.isNotEmpty(ids)){
                eq.in(TenderBidDetail::getBidId,ids);
            }
            eq.orderByAsc(TenderBidDetail::getRowNo);
            final List<TenderBidDetail> list = tenderBidDetailService.list(eq);
            //把报价为空的供应商和物料全部查询出来，然后去价格信息表中进行
            //键是供应商id 值是为空报价的物料报价明细
            Map<Long, List<TenderBidDetail>> result = list.stream()
                    .collect(Collectors.groupingBy(TenderBidDetail::getSupplierId))
                    .entrySet().stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            e -> e.getValue().stream()
                                    .filter(detail -> detail.getTaxPrice() == null || detail.getTaxPrice().compareTo(BigDecimal.ZERO) == 0)
                                    .collect(Collectors.toList())
                    ));
            //合并所有未报价的物料用于查询价格
            List<String> materialCodes = list.stream()
                    .filter(detail -> detail.getTaxPrice() != null && detail.getTaxPrice().compareTo(BigDecimal.ZERO) > 0)
                    .map(TenderBidDetail::getMaterialCode)
                    .collect(Collectors.toSet()) // 使用Set去重
                    .stream() // 再转换回List
                    .collect(Collectors.toList());
            //状态10 已定标待发布时直接查排名信息 增加状态查询
            if(CollectionUtils.isNotEmpty(materialCodes) && (tender.getStatus().intValue() == 2 || tender.getStatus().intValue() == 3 || tender.getStatus().intValue() == 4 || tender.getStatus().intValue() == 98)){
                //到价格表里查找有效且时间是最近的通过价格有效日期开始和结束日期
                List<PriceInfoClientDTO> effectiveMinPrice = priceInfoClient.getEffectiveMinPrice(materialCodes, new Date());
                Map<String, BigDecimal> priceMap = new HashMap<>();
                for (PriceInfoClientDTO dto : effectiveMinPrice) {
                    priceMap.put(dto.getMaterialCode(), dto.getConversionPrice());
                }
                //供应商未报价
                Map<Long, BigDecimal> countPriceMap = new HashMap<>();
                for (Map.Entry<Long, List<TenderBidDetail>> entry : result.entrySet()) {
                    Long supplierId = entry.getKey(); // 获取supplierId
                    List<TenderBidDetail> details = entry.getValue(); // 获取details列表
                    BigDecimal totalDetailAmount = BigDecimal.ZERO;
                    for (TenderBidDetail detail : details) {
                        String materialCode = detail.getMaterialCode(); // 获取MaterialCode
                        if(priceMap.containsKey(materialCode)){
                            BigDecimal price = priceMap.getOrDefault(materialCode, BigDecimal.ZERO);
                            //设置价格，计算公式 转换后价格 * 投标数量 count
                            BigDecimal detailAmount = price.multiply(detail.getCount() == null ? BigDecimal.ZERO:detail.getCount()).setScale(2, RoundingMode.DOWN);
                            totalDetailAmount = totalDetailAmount.add(detailAmount);
                        }
                    }
                    countPriceMap.put(supplierId, totalDetailAmount);//供应商对应的 未报价物料的未税总价格
                }

                //将总价设置到TenderBid数据信息里
                filteredBids.forEach(tenderBid -> {
                    Long supplierId = tenderBid.getSupplierId();
                    BigDecimal bigDecimal = countPriceMap.get(supplierId);
                    tenderBid.setFinalCnyAmount(tenderBid.getFinalCnyAmount() == null ?bigDecimal : tenderBid.getFinalCnyAmount().add(bigDecimal));
                });
                // 使用Comparator对tenderBids进行排序
                Collections.sort(filteredBids, Comparator.comparing(TenderBid::getFinalCnyAmount,Comparator.nullsLast(Comparator.naturalOrder())));
                // 设置排名 setRanking
                //选择“呆滞销售招标”时，系统按“单价越高排名越前”的规则进行报价排名；
                if ( "1".equals(tender.getTendType())){
                    Collections.sort(tenderBids, Comparator.comparing(TenderBid::getFinalCnyAmount,Comparator.nullsLast(Comparator.reverseOrder())));
                }
                int rank = 1;
                BigDecimal previousAmount = BigDecimal.valueOf(Double.MIN_VALUE);
                for (TenderBid bid : tenderBids) {
                    BigDecimal finalCnyAmount = bid.getFinalCnyAmount();
                    if(finalCnyAmount == null ){
                        finalCnyAmount = BigDecimal.ZERO;
                    }
                    if (finalCnyAmount.compareTo(previousAmount) != 0) {
                        previousAmount = finalCnyAmount;
                        bid.setRanking(rank);
                    }
                    rank++;
                }
            }
        }

        //需要进行排名设置
        if(CollectionUtils.isNotEmpty(filteredBids)){
// 1. 将 filteredBids1 转换为 Map<id, TenderBid>
            Map<Long, TenderBid> idToBidMap = filteredBids.stream()
                    .collect(Collectors.toMap(TenderBid::getId, Function.identity()));
// 2. 遍历 filteredBids 更新匹配的实体
            tenderBids.forEach(bid -> {
                TenderBid targetBid = idToBidMap.get(bid.getId());
                if (targetBid != null) {
                    targetBid.setRanking(bid.getRanking());
                }
            });

        }

        //2025-03-20
        final List<TenderBidBaseDTO> tenderBidDTOS = tenderBidConvert.entities2Dtos(tenderBids);
        modelAggregationService.processRelationAggregation(tenderBidDTOS);
        //判断是否需要显示排名
        final TenderSettingCompetitive byId = tenderSettingCompetitiveService.getById(id);
        if (Objects.isNull(byId.getInnerRankFlag()) || byId.getInnerRankFlag().equals(FlagConst.N.getCode())) {
            tenderBidDTOS.forEach(a -> a.setRanking(null));
        }
        return PageUtil.getPV(tenderBidDTOS, tenderBidDTOS.size());
    }




    @Override
    public List<TenderDetailByIdPO> zblistFindByList(Long zbId) {
        List<TenderDetailByIdPO> tenderSuppliers = tenderService.zblistFindByList(zbId);
        if (tenderSuppliers != null) {
            List<String> ids = tenderSuppliers.stream().map(TenderDetailByIdPO::getSupplierId).distinct()
                    .collect(Collectors.toList());
            List<SupplierDTO> supps = supplierClient.getSupplierByIds(ids);
            Long keys = System.currentTimeMillis();

            Map<Long, List<SupplierDTO>> spMap = null;
            if (supps != null) {
                spMap = supps.stream().collect(Collectors.groupingBy(SupplierDTO::getId));
            }
            Map<Long, List<SupplierDTO>> finalSpMap = spMap;
            tenderSuppliers.stream().forEach(a -> {
                List<SupplierDTO> dtos =
                        finalSpMap != null && finalSpMap.containsKey(Long.valueOf(a.getSupplierId())) ? finalSpMap.get(
                                Long.valueOf(a.getSupplierId())) : null;
                a.setSupplierCode(dtos != null ? dtos.get(0).getSupplierCode() : "");
                a.setSupplierName(dtos != null ? dtos.get(0).getSupplierName() : "");
                a.setUuidKey(keys);
                a.setDataSources(1);
            });
            redisTemplate.opsForValue()
                    .set(String.valueOf(keys), JSON.toJSONString(tenderSuppliers), 1, TimeUnit.HOURS);
        }
        return tenderSuppliers;
    }


}
