package com.ruoyi.project.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.SpecialCharacterEscaper;
import com.ruoyi.project.business.domain.TbCurrency;
import com.ruoyi.project.business.domain.TqQuotation;
import com.ruoyi.project.business.domain.vo.currency.CurrencyReq;
import com.ruoyi.project.business.domain.vo.currency.CurrencyRes;
import com.ruoyi.project.business.domain.vo.currency.CurrencySaveReq;
import com.ruoyi.project.business.enums.DelFlagEnum;
import com.ruoyi.project.business.mapper.TbCurrencyMapper;
import com.ruoyi.project.business.service.ITbCurrencyService;
import com.ruoyi.project.business.service.quotation.ITqQuotationService;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 币种汇率Service业务层处理
 *
 * @author ruoyi
 * @date 2024-05-14
 */
@Service
@RequiredArgsConstructor
public class TbCurrencyServiceImpl extends ServiceImpl<TbCurrencyMapper, TbCurrency> implements ITbCurrencyService {

    private final ITqQuotationService tqQuotationService;

    /**
     * 查询币种汇率列表
     *
     * @param currencyReq 币种汇率
     * @return 币种汇率
     */
    @Override
    public List<TbCurrency> selectTbCurrencyList(CurrencyReq currencyReq) {
        //// 构建查询条件
        //Wrapper<TbCurrency> wrapper = Wrappers.<TbCurrency>lambdaQuery()
        //        .like(StringUtils.isNotBlank(currencyReq.getCurrencyName()), TbCurrency::getCurrencyName, currencyReq.getCurrencyName())
        //        .eq(currencyReq.getExchangeRate() != null, TbCurrency::getExchangeRate, currencyReq.getExchangeRate())
        //        .between(currencyReq.getBeginTime() != null && currencyReq.getEndTime() != null, TbCurrency::getBeginTime, currencyReq.getBeginTime(), currencyReq.getEndTime())
        //        .like(StringUtils.isNotBlank(currencyReq.getRemark()), TbCurrency::getRemark, currencyReq.getRemark());
        //wrapper.getExpression()
        //        .add(Wrappers.<SysUser>lambdaQuery()
        //                .like(StringUtils.isNotBlank(currencyReq.getCreateUserNick()), SysUser::getNickName, currencyReq.getCreateUserNick()));
        //
        //return baseMapper.selectTbCurrencyList2(wrapper);
        SpecialCharacterEscaper.escapeSpecialCharacters(currencyReq, CurrencyReq::getCreateUserNick);
        return baseMapper.selectTbCurrencyList(currencyReq);

    }

    @Override
    public boolean add(CurrencySaveReq tbCurrency) {
        if (tbCurrency.getDateRange().size() == 2) {
            tbCurrency.setEffectiveDate(tbCurrency.getDateRange().get(0).atStartOfDay());
            tbCurrency.setExpirationDate(LocalDateTime.of(tbCurrency.getDateRange().get(1), LocalTime.MAX));
        }

        // 校验有效时间范围不能重叠
        validOverlap(tbCurrency);

        return save(tbCurrency);

    }

    @Override
    public List<TbCurrency> getUsableCurrencyRate() {
        return this.list(Wrappers.<TbCurrency>lambdaQuery()
            .le(TbCurrency::getEffectiveDate, DateUtils.getNowDate())
            .ge(TbCurrency::getExpirationDate, DateUtils.getNowDate())
            .eq(TbCurrency::getDelFlag, DelFlagEnum.NORMAL.getValue())
        );
    }

    @Override
    public CurrencyRes getInfo(Long currencyId) {
        TbCurrency currency = getById(currencyId);
        CurrencyRes currencyRes = new CurrencyRes();
        BeanUtils.copyProperties(currency, currencyRes);
        currencyRes.setDateRange(
            Arrays.asList(currency.getEffectiveDate().toLocalDate(), currency.getExpirationDate().toLocalDate()));
        return currencyRes;
    }

    @Override
    public List<TbCurrency> listAll() {
        return this.list();
    }

    @Override
    public boolean edit(CurrencySaveReq tbCurrency) {
        if (tbCurrency.getDateRange().size() == 2) {
            tbCurrency.setEffectiveDate(tbCurrency.getDateRange().get(0).atStartOfDay());
            // tbCurrency.setExpirationDate(LocalDateTime.of(tbCurrency.getDateRange().get(1), LocalTime.MAX));
            // 使用上面的方式会导致数据库保存的时间四舍五入变成第二天的起始
            // 手动添加 23:59:59
            LocalDate date = tbCurrency.getDateRange().get(1);
            tbCurrency.setExpirationDate(
                LocalDateTime.of(date.getYear(), date.getMonth(), date.getDayOfMonth(), 23, 59, 59));
        }

        // 校验有效时间范围不能重叠
        validOverlap(tbCurrency);

        return updateById(tbCurrency);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean remove(List<Long> ids) {
        // 校验 tqQuotationService 中是否已经使用该币种
        List<Long> currencyIds = tqQuotationService.list(
                Wrappers.<TqQuotation>lambdaQuery().in(TqQuotation::getCurrencyId, ids))
            .stream().map(TqQuotation::getCurrencyId).distinct().collect(Collectors.toList());
        if (!currencyIds.isEmpty()) {
            // 抛异常：哪些币种已经被使用
            List<TbCurrency> tbCurrencies = listByIds(currencyIds);
            throw new RuntimeException(MessageUtils.message("currency.error.currencyUsed",
                tbCurrencies.stream().map(TbCurrency::getCurrencyName).toArray()));
        }
        return removeBatchByIds(ids);
    }

    /**
     * 校验有效时间范围不能重叠 更新时排除当前记录
     *
     * @param tbCurrency 币种信息
     */
    private void validOverlap(CurrencySaveReq tbCurrency) {
        // 根据币种名称查询币种信息，校验有效时间范围不能重叠 , 排除当前记录
        LocalDateTime effectiveDate = tbCurrency.getEffectiveDate();
        LocalDateTime expirationDate = tbCurrency.getExpirationDate();

        LambdaQueryWrapper<TbCurrency> wrapper = Wrappers.lambdaQuery(TbCurrency.class).last(" limit 1")
            .eq(TbCurrency::getCurrencyName, tbCurrency.getCurrencyName())
            .and(item ->
                item.ge(TbCurrency::getEffectiveDate, effectiveDate).le(TbCurrency::getEffectiveDate, expirationDate)
                    .or(k -> k.le(TbCurrency::getEffectiveDate, effectiveDate)
                        .ge(TbCurrency::getExpirationDate, expirationDate))
                    .or(m -> m.ge(TbCurrency::getExpirationDate, effectiveDate)
                        .le(TbCurrency::getExpirationDate, expirationDate))
            )
            .ne(tbCurrency.getCurrencyId() != null, TbCurrency::getCurrencyId, tbCurrency.getCurrencyId());

        // 存在重叠
        boolean existOverlap = baseMapper.exists(wrapper);
        if (existOverlap) {
            throw new RuntimeException(MessageUtils.message("currency.error.dateRangeOverlap"));
        }
    }
}
