package com.yh.saas.plugin.news.service.impl;

import com.alipay.sofa.runtime.api.annotation.SofaReference;
import com.alipay.sofa.runtime.api.annotation.SofaService;
import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.winsea.svc.base.base.entity.CommonCompany;
import com.winsea.svc.base.base.service.ICommonCompanyService;
import com.winsea.svc.base.security.util.AuthSecurityUtils;
import com.yh.saas.plugin.news.entity.ExchangeRate;
import com.yh.saas.plugin.news.entity.view.ExchangeRateView;
import com.yh.saas.plugin.news.mapper.ExchangeRateMapper;
import com.yh.saas.plugin.news.service.IExchangeRateService;
import com.yh.saas.common.support.util.BeanUtils;
import com.yh.saas.common.support.util.query.QueryUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 记录汇率库信息 服务实现类
 * </p>
 *
 * @author zhaojz
 * @since 2019-11-26
 */
@Slf4j
@SofaService
public class ExchangeRateServiceImpl extends ServiceImpl<ExchangeRateMapper, ExchangeRate>
        implements IExchangeRateService {

    @SofaReference
    private ICommonCompanyService companyService;

    @Override
    public Double getExchangeRate(String currencyKey, String yearMonth) {
        Double rateValue = null;
        ExchangeRate exchangeRate = this.selectOne(new EntityWrapper<ExchangeRate>()
                .eq(ExchangeRate.QueryFileds.COMP_ID, AuthSecurityUtils.getCurrentUserInfo().getCompId())
                .eq(ExchangeRate.QueryFileds.CURRENCY_KEY, currencyKey)
                .eq(ExchangeRate.QueryFileds.YEAR_MONTH, yearMonth));
        if (exchangeRate != null) {
            rateValue = exchangeRate.getExchangeRate();
        } else {
            CommonCompany company = companyService.selectById(AuthSecurityUtils.getCurrentUserInfo().getCompId());
            if (company != null && StringUtils.equals(company.getOrganizationMonetaryKey(), currencyKey)) {
                rateValue = 1.0000;
            }
        }
        return rateValue;
    }

    @Override
    public List<ExchangeRate> getListByCondition(ExchangeRate example) {
        example.setCompId(AuthSecurityUtils.getCurrentUserInfo().getCompId());
        Wrapper<ExchangeRate> wrapper = QueryUtils.convertExampleToWrapper(example);
        wrapper.like(ExchangeRate.QueryFileds.YEAR_MONTH, example.getRateYearMonth(), SqlLike.RIGHT);
        return this.selectList(wrapper);
    }

    @Override
    @Transactional
    public void saveRate(List<ExchangeRateView> rateViewList) {
        ExchangeRate example = new ExchangeRate();
        example.setCompId(AuthSecurityUtils.getCurrentUserInfo().getCompId());
        example.setRateYearMonth(rateViewList.get(0).getYear());
        List<ExchangeRate> changeRates = this.getListByCondition(example);
        Map<String, ExchangeRate> oldRateMap = changeRates.stream().collect(Collectors
                .toMap(k -> k.getRateYearMonth() + "_" + k.getCurrencyKey(), Function.identity(), (a, b) -> a));
        Map<String, String> oldIdMap = changeRates.stream().collect(Collectors
                .toMap(k -> k.getRateYearMonth() + "_" + k.getCurrencyKey(), ExchangeRate::getId, (a, b) -> a));

        List<ExchangeRate> rateList = rateViewList.stream().map(rateView -> {
            List<ExchangeRate> rates = Lists.newArrayList();
            try {
                rates = this.getRateInfos(rateView);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            return rates;
        }).flatMap(List::stream).collect(Collectors.toList());
        Map<String, ExchangeRate> newRateMap = rateList.stream().collect(Collectors
                .toMap(k -> k.getRateYearMonth() + "_" + k.getCurrencyKey(), Function.identity(), (a, b) -> a));

        List<ExchangeRate> changeRateList = Lists.newArrayList();
        for (Map.Entry<String, ExchangeRate> map : newRateMap.entrySet()) {
            ExchangeRate oldRateInfo = oldRateMap.get(map.getKey());
            ExchangeRate newRateInfo = map.getValue();
            // 新增的汇率
            if (oldRateInfo == null) {
                newRateInfo.setCompId(example.getCompId());
                changeRateList.add(newRateInfo);
                continue;
            }
            // 修改的汇率
            if (this.isChanged(oldRateInfo.getExchangeRate(), newRateInfo.getExchangeRate())) {
                newRateInfo.setId(oldRateInfo.getId());
                changeRateList.add(newRateInfo);
            }
            oldIdMap.remove(map.getKey());
        }

        if (CollectionUtils.isNotEmpty(changeRateList)) {
            this.insertOrUpdateBatch(changeRateList);
        }
        // 删除清空的汇率
        if (CollectionUtils.isNotEmpty(oldIdMap.values())) {
            this.deleteBatchIds(oldIdMap.values());
        }
    }

    /**
     * 判断汇率是否被修改
     *
     * @param oldRate
     * @param newRate
     * @return
     */
    private boolean isChanged(Double oldRate, Double newRate) {
        if (oldRate == null && newRate == null) {
            return false;
        }
        if (oldRate != null && newRate == null || oldRate == null) {
            return true;
        }
        return Double.compare(oldRate, newRate) != 0;
    }

    /**
     * 通过反射获得字段值
     *
     * @param rateView
     * @return
     * @throws Exception
     */
    private List<ExchangeRate> getRateInfos(ExchangeRateView rateView) throws Exception {
        List<ExchangeRate> rates = Lists.newArrayList();
        for (int i = 1; i <= 12; i++) {
            String monthNo = String.format("%02d", i);
            Method method = rateView.getClass().getDeclaredMethod("getMonth" + monthNo);
            String rateValue = (String) method.invoke(rateView);
            if (StringUtils.isBlank(rateValue)) {
                continue;
            }
            ExchangeRate rate = BeanUtils.map(rateView, ExchangeRate.class);
            rate.setRateYearMonth(rateView.getYear() + "-" + monthNo);
            rate.setExchangeRate(Double.parseDouble(rateValue));
            rates.add(rate);
        }
        return rates;
    }

    /**
     * 查询当前公司某币种某月份汇率
     */
    @Override
    public Double getExchangeRateByCurrencyKeyAndDate(ExchangeRate info){
        Double rateValue = 1.00;
        // 查询汇率
        ExchangeRate view = baseMapper.getExchangeRateByCurrencyKeyAndDate(info);
        if (view != null) {
            rateValue = view.getExchangeRate();
        } else {
            CommonCompany company = companyService.selectById(AuthSecurityUtils.getCurrentUserInfo().getCompId());
            if (company != null && StringUtils.equals(company.getOrganizationMonetaryKey(), info.getCurrencyKey())) {
                rateValue = 1.0000;
            }
        }
        return rateValue;
    }

}
