package com.fjhx.jxst.service.sales.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.account.entity.account.po.AccountManagement;
import com.fjhx.account.service.account.AccountManagementService;
import com.fjhx.area.utils.CustomizeAreaUtil;
import com.fjhx.common.entity.corporation.po.Corporation;
import com.fjhx.common.enums.CodingRuleEnum;
import com.fjhx.common.service.coding.CodingRuleService;
import com.fjhx.common.service.corporation.CorporationService;
import com.fjhx.common.utils.Assert;
import com.fjhx.customer.entity.customer.po.Customer;
import com.fjhx.customer.entity.customer.po.CustomerUser;
import com.fjhx.customer.service.customer.CustomerService;
import com.fjhx.customer.service.customer.CustomerUserService;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.jxst.entity.sales.dto.SalesContractDto;
import com.fjhx.jxst.entity.sales.dto.SalesContractSelectDto;
import com.fjhx.jxst.entity.sales.po.SalesContract;
import com.fjhx.jxst.entity.sales.po.SalesContractDetails;
import com.fjhx.jxst.entity.sales.vo.SalesContractDetailsVo;
import com.fjhx.jxst.entity.sales.vo.SalesContractVo;
import com.fjhx.jxst.entity.statement.bo.SettlementBo;
import com.fjhx.jxst.mapper.sales.SalesContractMapper;
import com.fjhx.jxst.service.sales.SalesContractDetailsService;
import com.fjhx.jxst.service.sales.SalesContractService;
import com.ruoyi.common.core.domain.BasePo;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.common.utils.wrapper.SqlField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * <p>
 * 销售合同 服务实现类
 * </p>
 *
 * @author
 * @since 2023-05-16
 */
@Service
public class SalesContractServiceImpl extends ServiceImpl<SalesContractMapper, SalesContract> implements SalesContractService {

    @Autowired
    private SalesContractDetailsService salesContractDetailsService;
    @Autowired
    private CustomerService customerService;
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private CustomerUserService customerUserService;
    @Autowired
    private AccountManagementService accountManagementService;
    @Autowired
    private CorporationService corporationService;
    @Autowired
    private CodingRuleService codingRuleService;

    @Override
    public Page<SalesContractVo> getPage(SalesContractSelectDto dto) {
        IWrapper<SalesContract> wrapper = getWrapper();
        if (ObjectUtil.isNotEmpty(dto.getKeyword())) {
            List<Customer> list = customerService.list(q -> q.like(Customer::getName, dto.getKeyword()));
            if (ObjectUtil.isNotEmpty(list)) {
                List<Long> ids = list.stream().map(Customer::getId).collect(Collectors.toList());
                wrapper.and(q -> q.in(SalesContract::getCustomerId, ids).or().like(SalesContractVo::getContractAmount, dto.getKeyword()));
            } else {
                wrapper.and(q -> q
                        .like(SalesContractVo::getContractAmount, dto.getKeyword())
                        .or().like(SalesContract::getCode, dto.getKeyword())
                );
            }
        }

        //是否结清过滤
        wrapper.eq("sc", SalesContractSelectDto::getIsSettled, dto.getIsSettled());

        wrapper.orderByDesc("sc", SalesContract::getId);
        Page<SalesContractVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<SalesContractVo> records = page.getRecords();
        //赋值客户名称
        customerService.attributeAssign(records, SalesContractVo::getCustomerId, (item, customer) -> {
            item.setCustomerName(customer.getName());
        });

        //计算未到账金额(未结清金额)
        records.forEach(item -> item.setNotClaimAmount(item.getContractAmount().subtract(item.getClaimAmount())));

        return page;
    }

    @Override
    public SalesContractVo detail(Long id) {
        SalesContract salesContract = this.getById(id);
        Assert.notEmpty(salesContract, "查询不到合同信息");
        SalesContractVo result = BeanUtil.toBean(salesContract, SalesContractVo.class);
        List<SalesContractDetails> salesContractDetailsList = salesContractDetailsService.list(q -> q.eq(SalesContractDetails::getSalesContractId, result.getId()));
        List<SalesContractDetailsVo> salesContractDetailsVos = BeanUtil.copyToList(salesContractDetailsList, SalesContractDetailsVo.class);
        //赋值产品信息
        productInfoService.attributeAssign(salesContractDetailsVos, SalesContractDetailsVo::getProductId, (item, productInfo) -> {
            item.setProductName(productInfo.getName());
            item.setProductSpec(productInfo.getSpec());
            item.setProductUnit(productInfo.getUnit());
        });
        result.setContractDetailsList(salesContractDetailsVos);
        //赋值客户信息
        Customer customer = customerService.getById(result.getCustomerId());
        if (ObjectUtil.isNotEmpty(customer)) {
            result.setCustomerName(customer.getName());
            result.setCustomerBank(customer.getBeneficiaryBank());
            result.setCustomerSwiftCode(customer.getSwiftCode());
            result.setCustomerAccountNumber(customer.getBeneficiaryAccountNumber());

            //赋值客户国省市名称
            Map<Long, String> areaMapByIds = CustomizeAreaUtil.getAreaMapByIds(Arrays.asList(
                    customer.getCountryId(),
                    customer.getProvinceId(),
                    customer.getCityId())
            );
            result.setBuyCountryName(areaMapByIds.get(customer.getCountryId()));
            result.setBuyProvinceName(areaMapByIds.get(customer.getProvinceId()));
            result.setBuyCityName(areaMapByIds.get(customer.getCityId()));
            result.setBuyAddress(customer.getAddress());
            result.setBuyDutyParagraph(customer.getDutyParagraph());
        }
        //赋值客户更多联系人
        List<CustomerUser> customerUserList = customerUserService.list(q -> q.eq(CustomerUser::getCustomerId, salesContract.getCustomerId()));
        result.setCustomerUserList(customerUserList);

        //赋值卖方信息多公司
        AccountManagement accountManagement = accountManagementService.getById(result.getShroffAccountId());
        Corporation corporation = corporationService.getById(result.getSellCorporationId());
        result.setSellCorporationName(corporation.getName());
        result.setSellCorporationNumber(corporation.getCorporationNumber());
        result.setSellTaxationCode(corporation.getTaxationCode());

        result.setSellAccountName(accountManagement.getName());
        result.setSellOpeningBank(accountManagement.getOpeningBank());
        result.setSellInterbankNumber(accountManagement.getInterbankNumber());
        result.setSellAccountOpening(accountManagement.getAccountOpening());

        return result;
    }

    @DSTransactional
    @Override
    public void add(SalesContractDto salesContractDto) {
        List<SalesContractDetails> salesContractDetailsList = salesContractDto.getSalesContractDetailsList();
//        BigDecimal count = BigDecimal.ZERO;
//        for (SalesContractDetails salesContractDetails : salesContractDetailsList) {
//            count = count.add(salesContractDetails.getUnitPrice().multiply(salesContractDetails.getQuantity()));
//        }
//        salesContractDto.setContractAmount(count);
//        salesContractDto.setCode(CodeEnum.SALES_CONTRACT.getCode());
        salesContractDto.setCode(codingRuleService.createCode(CodingRuleEnum.JXST_SALES_CONTRACT.getKey(), null));

        this.save(salesContractDto);
        for (SalesContractDetails salesContractDetails : salesContractDetailsList) {
            salesContractDetails.setSalesContractId(salesContractDto.getId());
        }
        salesContractDetailsService.saveBatch(salesContractDetailsList);
    }

    /**
     * 合同结清
     */
    @Override
    public void settle(SalesContractDto dto) {
        this.update(q -> q
                .eq(BasePo::getId, dto.getId())
                .set(BasePo::getUpdateTime, new Date())
                .set(BasePo::getUpdateUser, SecurityUtils.getUserId())
                .set(SalesContract::getIsSettled, 1)
        );
    }


    /**
     * 利润结算表
     */
    @Override
    public Page<SettlementBo> getProfitClearingPage(SalesContractSelectDto dto) {
        IWrapper<SalesContract> wrapper = getProfitClearingWrapper(dto);
        wrapper.orderByDesc("sc", SalesContract::getCreateTime);
        Page<SettlementBo> profitClearingPage = baseMapper.getProfitClearingPage(dto.getPage(), wrapper);
        List<SettlementBo> records = profitClearingPage.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return profitClearingPage;
        }

        //计算 总支出 毛利 毛利率
        for (SettlementBo record : records) {
            //总支出
            BigDecimal totalExpenditure = BigDecimal.ZERO;
            totalExpenditure.add(record.getMaterialFee());//物料费
            totalExpenditure.add(record.getAfterSalesFee());//售后费用
            totalExpenditure.add(record.getTrailerFee());//拖车费
            totalExpenditure.add(record.getInspectionRedPackFee());//验货红包
            totalExpenditure.add(record.getCommissionFee());//佣金
            totalExpenditure.add(record.getOtherFee());//其他费用
            record.setTotalExpenditure(totalExpenditure);

            //毛利(总收入-总支出)
            record.setGrossProfit(record.getTotalIncome().subtract(record.getTotalExpenditure()));

            //毛利率(毛利/总收入*100%)
            BigDecimal grossProfitMargin = BigDecimal.ZERO;
            if (record.getGrossProfit().compareTo(BigDecimal.ZERO) > 0) {
                grossProfitMargin = record.getGrossProfit()
                        .divide(record.getTotalIncome(), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            }
            record.setGrossProfitMargin(grossProfitMargin);

            //变成科学计数法问题处理
            record.setMaterialFee(record.getMaterialFee().setScale(4, RoundingMode.HALF_UP));
        }

        return profitClearingPage;
    }

    /**
     * 利润结算表头部统计
     */
    @Override
    public SettlementBo getProfitClearingHead(SalesContractSelectDto dto) {
        IWrapper<SalesContract> wrapper = getProfitClearingWrapper(dto);
        SettlementBo record = baseMapper.getProfitSettlementHead(wrapper);

        //总支出
        BigDecimal totalExpenditure = BigDecimal.ZERO;
        totalExpenditure.add(record.getMaterialFee());//物料费
        totalExpenditure.add(record.getAfterSalesFee());//售后费用
        totalExpenditure.add(record.getTrailerFee());//拖车费
        totalExpenditure.add(record.getInspectionRedPackFee());//验货红包
        totalExpenditure.add(record.getCommissionFee());//佣金
        totalExpenditure.add(record.getOtherFee());//其他费用
        record.setTotalExpenditure(totalExpenditure);

        //毛利(总收入-总支出)
        record.setGrossProfit(record.getTotalIncome().subtract(record.getTotalExpenditure()));

        //毛利率(毛利/总收入*100%)
        BigDecimal grossProfitMargin = BigDecimal.ZERO;
        if (record.getGrossProfit().compareTo(BigDecimal.ZERO) > 0) {
            grossProfitMargin = record.getGrossProfit()
                    .divide(record.getTotalIncome(), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
        }
        record.setGrossProfitMargin(grossProfitMargin);

        //变成科学计数法问题处理
        record.setMaterialFee(record.getMaterialFee().setScale(4, RoundingMode.HALF_UP));

        return record;
    }

    /**
     * 利润结算表公用参数列表
     */
    private IWrapper<SalesContract> getProfitClearingWrapper(SalesContractSelectDto dto) {
        IWrapper<SalesContract> wrapper = IWrapper.getWrapper();
        wrapper.keyword(dto.getKeyword(),
                new SqlField("cu.name"),
                new SqlField("sc.code")
        );

        wrapper.eq("sc.is_settled", dto.getIsSettled());


        wrapper.like("cu.name",dto.getCustomerName());
        wrapper.like("sc.code",dto.getSalesContractCode());

        wrapper.ge("sc",SalesContract::getCreateTime,dto.getBeginTime());
        wrapper.le("sc",SalesContract::getCreateTime,dto.getEndTime());

        return wrapper;
    }

    /**
     * 预算
     */
    @Override
    public void budget(SalesContractDto dto) {
        Assert.notEmpty(dto.getId(), "");
        SalesContract salesContract = this.getById(dto.getId());
        Assert.notEmpty(salesContract,"查询不到合同信息！");
        this.updateById(dto);
    }
}
