package com.jy.business.contract.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jy.business.capital.dao.CapitalTransactionsDao;
import com.jy.business.capital.model.entity.CapitalTransactions;
import com.jy.business.capital.model.vo.CapitalTransactionsVo;
import com.jy.business.contract.dao.ContractDetailDao;
import com.jy.business.contract.dao.ContractInfoDao;
import com.jy.business.contract.model.dto.ContractInfoDto;
import com.jy.business.contract.model.dto.ContractInfoSelectDto;
import com.jy.business.contract.model.entity.ContractDetail;
import com.jy.business.contract.model.entity.ContractInfo;
import com.jy.business.contract.model.vo.ContractInfoVo;
import com.jy.business.contract.model.vo.ContractStatisticsVo;
import com.jy.business.contract.model.vo.TransactionVo;
import com.jy.business.contract.service.ContractInfoService;
import com.jy.business.payment.model.entity.PaymentRequestsDetail;
import com.jy.framework.model.base.BaseIdPo;
import com.jy.framework.utils.AssertUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 合同 服务实现类
 * </p>
 *
 * @author
 * @since 2025-06-10
 */
@Service
public class ContractInfoServiceImpl implements ContractInfoService {

    @Resource
    private ContractInfoDao contractInfoDao;

    @Resource
    private ContractDetailDao contractDetailDao;

    @Resource
    private CapitalTransactionsDao capitalTransactionsDao;

    @Override
    public List<ContractStatisticsVo> getStatistics(ContractInfoSelectDto dto) {
        List<ContractStatisticsVo> list = contractInfoDao.getStatistics(dto);

        int contractQuantity = 0;
        BigDecimal contractAmount = BigDecimal.ZERO;
        BigDecimal fundReceivedAmount = BigDecimal.ZERO;
        BigDecimal profit = BigDecimal.ZERO;

        ContractStatisticsVo contractStatisticsVo = new ContractStatisticsVo();
        for (ContractStatisticsVo item : list) {
            contractQuantity = contractQuantity + item.getContractQuantity();
            contractAmount = contractAmount.add(item.getContractAmount());
            fundReceivedAmount = fundReceivedAmount.add(item.getFundReceivedAmount());
            profit = profit.add(item.getProfit());
        }

        contractStatisticsVo.setContractQuantity(contractQuantity);
        contractStatisticsVo.setContractAmount(contractAmount);
        contractStatisticsVo.setFundReceivedAmount(fundReceivedAmount);
        contractStatisticsVo.setProfit(profit);
        contractStatisticsVo.setSellerCompany("合计");

        list.add(0, contractStatisticsVo);
        return list;
    }

    @Override
    public List<ContractInfoVo> getList(ContractInfoSelectDto dto) {
        return contractInfoDao.getList(dto);
    }

    @Override
    public Page<ContractInfoVo> getPage(ContractInfoSelectDto dto) {
        Page<ContractInfoVo> page = contractInfoDao.getPage(dto);
        List<ContractInfoVo> records = page.getRecords();

        if (records.isEmpty()) {
            return page;
        }

        // 合同id
        List<Long> idList = records.stream().map(BaseIdPo::getId).toList();

        // 到账金额
        Map<Long, List<CapitalTransactionsVo>> map = capitalTransactionsDao.getByContract(idList).stream()
                .collect(Collectors.groupingBy(CapitalTransactions::getContractId));

        // 请款金额
        Map<Long, List<PaymentRequestsDetail>> collect = contractInfoDao.getPaymentList(idList).stream()
                .collect(Collectors.groupingBy(PaymentRequestsDetail::getContractId));

        for (ContractInfoVo record : records) {
            List<CapitalTransactionsVo> capitalTransactionsList = map.get(record.getId());

            if (ObjectUtil.isEmpty(capitalTransactionsList)) {
                record.setReceivedAmount(BigDecimal.ZERO);
                record.setCapitalTransactionsList(Collections.emptyList());
            } else {
                capitalTransactionsList.forEach(item ->
                        item.setAmount(item.getAmount().multiply(record.getExchangeRate())));
                record.setReceivedAmount(
                        capitalTransactionsList.stream()
                                .map(CapitalTransactions::getAmount)
                                .reduce(BigDecimal.ZERO, BigDecimal::add)
                );
                record.setCapitalTransactionsList(capitalTransactionsList);
            }

            List<PaymentRequestsDetail> paymentRequestsDetails = collect.get(record.getId());
            if (ObjectUtil.isEmpty(paymentRequestsDetails)) {
                record.setProfit(record.getReceivedAmount());
            } else {
                record.setProfit(record.getReceivedAmount()
                        .subtract(paymentRequestsDetails.stream().map(PaymentRequestsDetail::getAmount)
                                .reduce(BigDecimal.ZERO, BigDecimal::add))
                );
            }
        }

        return page;
    }

    @Override
    public ContractInfoVo getDetail(Long id) {
        ContractInfoVo vo = contractInfoDao.getDetail(id);
        AssertUtil.notNull(vo, "未知数据");

        List<ContractDetail> list = contractDetailDao.list(q -> q.eq(ContractDetail::getContractId, id));
        vo.setList(list);
        return vo;
    }

    @Override
    public void add(ContractInfoDto dto) {
        contractInfoDao.save(dto);
    }

    @Override
    public void edit(ContractInfoDto dto) {
        contractInfoDao.updateById(dto);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<Long> idList) {
        contractInfoDao.removeBatchByIds(idList);
    }

    @Override
    public List<TransactionVo> getTransactionList(Long id) {
        return contractInfoDao.getTransactionList(id);
    }

    @Override
    public void settlement(ContractInfoDto dto) {
        contractInfoDao.update(q -> q
                .eq(BaseIdPo::getId, dto.getId())
                .set(ContractInfo::getHasSettlement, dto.getHasSettlement())
                .set(ContractInfo::getSettlementProfit, dto.getSettlementProfit())
        );
    }

}
