package com.yonge.cooleshow.biz.dal.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonge.cooleshow.biz.dal.dto.UserAccountRecordDto;
import com.yonge.cooleshow.biz.dal.dto.req.TotalReq;
import com.yonge.cooleshow.biz.dal.entity.UserAccountRecord;
import com.yonge.cooleshow.biz.dal.enums.CacheNameEnum;
import com.yonge.cooleshow.biz.dal.enums.FrozenTypeEnum;
import com.yonge.cooleshow.biz.dal.enums.TimeTypeEnum;
import com.yonge.cooleshow.biz.dal.service.UserAccountRecordService;
import com.yonge.cooleshow.biz.dal.support.DistributedLock;
import com.yonge.cooleshow.biz.dal.vo.res.AccountTotal;
import com.yonge.cooleshow.biz.dal.vo.res.HomeTotalTeacher;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.cooleshow.common.exception.BizException;
import com.yonge.toolset.utils.date.DateUtil;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yonge.cooleshow.biz.dal.entity.UserAccount;
import com.yonge.cooleshow.biz.dal.vo.UserAccountVo;
import com.yonge.cooleshow.biz.dal.dto.search.UserAccountSearch;
import com.yonge.cooleshow.biz.dal.dao.UserAccountDao;
import com.yonge.cooleshow.biz.dal.service.UserAccountService;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;


@Service
public class UserAccountServiceImpl extends ServiceImpl<UserAccountDao, UserAccount> implements UserAccountService {
    @Autowired
    private UserAccountRecordService userAccountRecordService;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public UserAccountVo detail(Long id) {
        UserAccountVo detail = baseMapper.detail(id);
        if (null == detail) {
            throw new BizException("用户没有开通账户");
        }
        return detail;
    }

    @Override
    public IPage<UserAccountVo> selectPage(IPage<UserAccountVo> page, UserAccountSearch query) {
        return page.setRecords(baseMapper.selectPage(page, query));
    }

    @Override
    public HttpResponseResult<UserAccountRecord> accountChange(UserAccountRecordDto accountRecordDto) {
        if (null == accountRecordDto.getUserId() || null == accountRecordDto.getTransAmount()
                || null == accountRecordDto.getInOrOut() || null == accountRecordDto.getBizType()) {
            throw new BizException("缺少参数");
        }

        Future<HttpResponseResult<UserAccountRecord>> httpResponseResultFuture = DistributedLock.of(redissonClient)
                .callIfLockCanGet(CacheNameEnum.LOCK_CHANGE_ACCOUNT.getRedisKey(accountRecordDto.getUserId())
                        , () -> doAccountChange(accountRecordDto), 60L, TimeUnit.SECONDS);

        try {
            return httpResponseResultFuture.get();
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException("账户变更失败");
        }
    }

    @Override
    public HttpResponseResult<AccountTotal> accountTotal(TotalReq totalReq) {
        List<AccountTotal> infoList = baseMapper.accountTotal(totalReq.getTimeType().getCode(), totalReq);

        BigDecimal practiceAmount = BigDecimal.ZERO;
        BigDecimal liveAmount = BigDecimal.ZERO;
        BigDecimal musicAmount = BigDecimal.ZERO;
        for (AccountTotal info : infoList) {
            info.setPracticeAmount(null == info.getPracticeAmount() ? BigDecimal.ZERO : info.getPracticeAmount());
            info.setLiveAmount(null == info.getLiveAmount() ? BigDecimal.ZERO : info.getLiveAmount());
            info.setMusicAmount(null == info.getMusicAmount() ? BigDecimal.ZERO : info.getMusicAmount());

            practiceAmount = practiceAmount.add(info.getPracticeAmount());
            liveAmount = liveAmount.add(info.getLiveAmount());
            musicAmount = musicAmount.add(info.getMusicAmount());
        }
        AccountTotal total = new AccountTotal();

        total.setTotalInAmount(practiceAmount.add(liveAmount).add(musicAmount));
        if (!BigDecimal.ZERO.equals(total.getTotalInAmount())) {
            total.setPracticeAmount(practiceAmount);
            BigDecimal practiceRate = total.getPracticeAmount()
                    .divide(total.getTotalInAmount(), 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
            total.setPracticeRate(practiceRate);

            total.setLiveAmount(liveAmount);
            BigDecimal liveRate = total.getLiveAmount()
                    .divide(total.getTotalInAmount(), 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
            total.setLiveRate(liveRate);

            total.setMusicAmount(musicAmount);
            BigDecimal musicRate = total.getMusicAmount()
                    .divide(total.getTotalInAmount(), 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
            total.setMusicRate(musicRate);
        }
        total.setInfoList(infoList);
        return HttpResponseResult.succeed(total);
    }

    private HttpResponseResult<UserAccountRecord> doAccountChange(UserAccountRecordDto accountRecordDto) {
        if (FrozenTypeEnum.FROZEN.equals(accountRecordDto.getFrozenType())) {
            baseMapper.frozenChangeAccount(accountRecordDto.getUserId(), accountRecordDto.getTransAmount(), accountRecordDto.getInOrOut().getCode());
        } else if (FrozenTypeEnum.FROZEN_DEDUCT.equals(accountRecordDto.getFrozenType())) {
            baseMapper.frozenDeductChangeAccount(accountRecordDto.getUserId(), accountRecordDto.getTransAmount(), accountRecordDto.getInOrOut().getCode());
        } else if (FrozenTypeEnum.FROZEN_BACK.equals(accountRecordDto.getFrozenType())) {
            baseMapper.frozenBackChangeAccount(accountRecordDto.getUserId(), accountRecordDto.getTransAmount(), accountRecordDto.getInOrOut().getCode());
        } else {
            baseMapper.changeAccount(accountRecordDto.getUserId(), accountRecordDto.getTransAmount(), accountRecordDto.getInOrOut().getCode());
        }

        UserAccountVo detail = detail(accountRecordDto.getUserId());
        if (detail.getAmountTotal().doubleValue() < 0
                || detail.getAmountUsable().doubleValue() < 0 || detail.getAmountFrozen().doubleValue() < 0) {
            throw new BizException("账户变更失败");
        }
        if (accountRecordDto.getSaveRecord()) {
            //插入账户变更记录
            accountRecordDto.setAccountId(accountRecordDto.getUserId());
            accountRecordDto.setAccountBalance(detail.getAmountUsable());
            userAccountRecordService.save(accountRecordDto);
        }
        return HttpResponseResult.succeed(accountRecordDto);
    }
}