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

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.auth.api.enums.SysUserType;
import com.yonge.cooleshow.biz.dal.dao.MusicSheetDao;
import com.yonge.cooleshow.biz.dal.dto.MusicSheetDto;
import com.yonge.cooleshow.biz.dal.dto.MusicSheetPayDto;
import com.yonge.cooleshow.biz.dal.dto.UserAccountRecordDto;
import com.yonge.cooleshow.biz.dal.dto.req.OrderReq;
import com.yonge.cooleshow.biz.dal.dto.req.TeacherMusicSheetAuditReq;
import com.yonge.cooleshow.biz.dal.dto.search.*;
import com.yonge.cooleshow.biz.dal.entity.*;
import com.yonge.cooleshow.biz.dal.enums.*;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.support.PageUtil;
import com.yonge.cooleshow.biz.dal.vo.*;
import com.yonge.cooleshow.biz.dal.vo.res.OrderCreateRes;
import com.yonge.cooleshow.common.constant.SysConfigConstant;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.cooleshow.common.exception.BizException;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
import com.yonge.toolset.utils.string.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * MusicSheetService服务实现类
 * @author yzp
 * @date 2022-03-26 00:01:37
 * @version v1.0
 **/
@Service
public class MusicSheetServiceImpl extends ServiceImpl<MusicSheetDao,MusicSheet> implements MusicSheetService {

    private static final  Logger log = LoggerFactory.getLogger(MusicSheetServiceImpl.class);

    @Autowired
    private MusicSheetDao musicSheetDao;

    @Autowired
    private MusicSheetAccompanimentService musicSheetAccompanimentService;

    @Autowired
    private MusicFavoriteService musicFavoriteService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private MusicSheetPurchaseRecordService musicSheetPurchaseRecordService;

    @Autowired
    private MusicSheetPracticeRecordService musicSheetPracticeRecordService;

    @Autowired
    private StudentService studentService;

    @Autowired
    private MusicSheetAuthRecordService musicSheetAuthRecordService;

    @Autowired
    private SysUserFeignService sysUserFeignService;

    @Autowired
    private SysMessageService sysMessageService;

    @Autowired
    private UserAccountService userAccountService;

    public MusicSheetDao getDao() {
        return musicSheetDao;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean saveMp3AndAccompaniment(MusicSheetDto musicSheetDto,Long userId) {
        MusicSheet musicSheet = new MusicSheet();
        BeanUtils.copyProperties(musicSheetDto, musicSheet);
        //保存主表
        musicSheet.setUpdateBy(userId);
        musicSheet.setUpdateTime(new Date());
        musicSheet.setState(YesOrNoEnum.NO);
        this.saveOrUpdate(musicSheet);

        Long sheetId = musicSheet.getId();
        List<MusicSheetAccompaniment> list = musicSheetDto.getBackground();
        list.forEach(musicSheetAccompaniment -> musicSheetAccompaniment.setMusicSheetId(sheetId).setCreateBy(userId).setCreateTime(new Date()));
        return musicSheetAccompanimentService.saveBatch(list);

    }

    @Override
    public IPage<MusicSheetVo> selectPage(IPage<MusicSheetVo> page, MusicSheetSearch query) {
        return page.setRecords(baseMapper.selectPage(page, query));

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean state(Long id) {
        MusicSheet musicSheet = this.getById(id);
        if (musicSheet == null) {
            throw  new BizException("未找到曲目信息");
        }
        if (YesOrNoEnum.NO.getCode().equals(musicSheet.getState().getCode())) {
            musicSheet.setState(YesOrNoEnum.YES);
        } else {
            musicSheet.setState(YesOrNoEnum.NO);
        }
        return this.updateById(musicSheet);

    }

    @Override
    public IPage<MusicSheetVo> selectAlbumDetailPage(IPage<MusicSheetVo> page, MusicAlbumDetailSearch query) {
        return page.setRecords(baseMapper.selectAlbumDetailPage(page, query));
    }

    @Override
    public MusicSheetShareVo shareMusicSheet(SysUser sysUser) {
        MusicSheetSearch query = new MusicSheetSearch();
        // 设置只查老师用户
        query.setCreateBy(sysUser.getId());
        query.setAuditStatus(AuthStatusEnum.PASS);
        query.setState(YesOrNoEnum.YES);
        query.setDelFlag(false);
        // 只查3条
        query.setRows(3);
        IPage<MusicSheetVo> musicSheetVoIPage = selectPage(PageUtil.getPage(query), query);
        MusicSheetShareVo musicSheetShareVo = new MusicSheetShareVo();
        musicSheetShareVo.setMusicSheetCount(musicSheetVoIPage.getTotal());
        musicSheetShareVo.setMusicSheetVoList(musicSheetVoIPage.getRecords());
        musicSheetShareVo.setName(sysUser.getUsername());
        musicSheetShareVo.setAvatar(sysUser.getAvatar());
        return musicSheetShareVo;
    }

    @Override
    public MusicSheetDetailVo detail(Long id, SysUser sysUser,SysUserType userType) {
        MusicSheetDetailVo detail = baseMapper.detail(id);
        if (detail == null) {
            throw new BizException("未找到曲目信息");
        }
        if (ChargeTypeEnum.FREE.getCode().equals(detail.getChargeType().getCode())) {
            detail.setPlay(YesOrNoEnum.YES);
        }  else if (SysUserType.STUDENT.getCode().equals(userType.getCode())) {
            detail.setPlay(YesOrNoEnum.NO);
            // 单曲购买 判断购买记录，有记录课播放
            if (ChargeTypeEnum.CHARGE.getCode().equals(detail.getChargeType().getCode())) {
                // 学生须判断是否能播放曲目
                MusicSheetPurchaseRecord musicSheetPurchaseRecord = musicSheetPurchaseRecordService.checkPurchase(
                        sysUser.getId(), detail.getId());
                if (musicSheetPurchaseRecord != null) {
                    detail.setOrderStatus(musicSheetPurchaseRecord.getOrderStatus());
                    if (OrderStatusEnum.PAID.getCode().equals(musicSheetPurchaseRecord.getOrderStatus().getCode())) {
                        detail.setPlay(YesOrNoEnum.YES);
                    }
                }
            } else if  (ChargeTypeEnum.VIP.getCode().equals(detail.getChargeType().getCode())) {
                // 会员 判断是否为会员， 会员可播放
                Student student = studentService.getById(sysUser.getId());
                if (new Date().compareTo(student.getMembershipEndTime()) < 0) {
                    detail.setPlay(YesOrNoEnum.YES);
                }
            }

        } else {
            detail.setPlay(YesOrNoEnum.YES);
        }
        // 学生进入云教练练习，添加一条练习记录
        musicSheetPracticeRecordService.addRecord(id,sysUser.getId());
        return detail;
    }

    @Override
    public IPage<MusicSheetVo> selectStudentPage(IPage<MusicSheetVo> page, StudentMusicSheetSearch query) {
        return page.setRecords(baseMapper.selectStudentMusicPage(page, query));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean setFavorite(Long userId, Long musicSheetId) {
        List<MusicFavorite> musicFavorites = musicFavoriteService.getFavorite(userId, musicSheetId);
        if (CollectionUtils.isEmpty(musicFavorites)) {
            MusicFavorite musicFavorite = new MusicFavorite();
            musicFavorite.setMusicSheetId(musicSheetId);
            musicFavorite.setUserId(userId);
            musicFavorite.setFavoriteTime(new Date());
            return musicFavoriteService.save(musicFavorite);
        } else {
            List<Long> ids = musicFavorites.stream().map(MusicFavorite::getId).collect(Collectors.toList());
            return musicFavoriteService.removeByIds(ids);
        }
    }

    @Override
    public IPage<MusicSheetVo> myMusic(IPage<MusicSheetVo> page, StudentMusicSheetSearch query) {
        return page.setRecords(baseMapper.selectMyMusicPage(page,query));
    }

    @Override
    public IPage<MusicSheetVo> favoriteMusic(IPage<MusicSheetVo> page, StudentMusicSheetSearch query) {
        return page.setRecords(baseMapper.selectFavoriteMusicPage(page,query));
    }

    @Override
    public IPage<MusicSheetVo> practiceMusic(IPage<MusicSheetVo> page, StudentMusicSheetSearch query) {
        // 预计最近练习表数据量会很多
        // 先找到最近练习的曲目id 在根据曲目id进行精确查找
        IPage<Long> practiceMusicIdPage = musicSheetPracticeRecordService.selectPracticeMusic(query,page.getPages(),page.getSize());
        List<Long> practiceMusicIdList = practiceMusicIdPage.getRecords();
        if (CollectionUtils.isEmpty(practiceMusicIdList)) {
            page.setRecords(new ArrayList<>());
            return page;
        }
        // 构建分页信息
        page.setRecords(baseMapper.selectPracticeMusicPage(query,practiceMusicIdList));
        page.setPages(practiceMusicIdPage.getPages());
        page.setCurrent(practiceMusicIdPage.getCurrent());
        page.setSize(practiceMusicIdPage.getSize());
        page.setTotal(practiceMusicIdPage.getTotal());
        return page;
    }

    @Override
    public IPage<StudentMusicSheetOrderVo> selectStudentOrderPage(IPage<StudentMusicSheetOrderVo> page, StudentMusicSheetOrderSearch query) {
        return page.setRecords(baseMapper.selectStudentOrderPage(page,query));
    }

    @Override
    public IPage<TeacherMusicSheetVo> selectTeacherPage(IPage<TeacherMusicSheetVo> page, TeacherMusicSheetSearch query) {
        return page.setRecords(baseMapper.selectTeacherPage(page,query));
    }

    @Override
    public IPage<TeacherMusicSheetVo> selectAuditPage(IPage<TeacherMusicSheetVo> page, TeacherMusicSheetAuditSearch query) {
        return page.setRecords(baseMapper.selectAuditPage(page,query));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean audit(TeacherMusicSheetAuditReq param, Long userId) {

        MusicSheet musicSheet = this.getById(param.getMusicSheetId());
        if (musicSheet == null) {
            throw  new BizException("未找到曲目信息");
        }
        if (!AuthStatusEnum.DOING.getCode().equals(musicSheet.getAuditStatus().getCode())) {
            throw  new BizException("曲目已经过审批");
        }

        boolean flag = false;
        if (musicSheetAuthRecordService.audit(param,userId)) {
            musicSheet.setAuditStatus(param.getAuthStatus());
            musicSheet.setUpdateBy(userId);
            musicSheet.setUpdateTime(new Date());
            flag =  this.updateById(musicSheet);
        }

        // 发送审核通知
        Map<Long,String> receivers = new HashMap<>();
        SysUser teacher = sysUserFeignService.queryUserById(musicSheet.getUserId());
        receivers.put(musicSheet.getUserId(), teacher.getPhone());
        if (AuthStatusEnum.PASS.getCode().equals(param.getAuthStatus().getCode())) {
            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.MUSIC_SHEET_AUTH_PASS,
                                               receivers,null,0,null,ClientEnum.TEACHER.getCode(),musicSheet.getMusicSheetName());
        } else if (AuthStatusEnum.UNPASS.getCode().equals(param.getAuthStatus().getCode())){
            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.MUSIC_SHEET_AUTH_UNPASS,
                                               receivers,null,0,null,ClientEnum.TEACHER.getCode(),musicSheet.getMusicSheetName(),param.getRemark());
        }

        return flag;
    }

    @Override
    public boolean del(Long id) {

        MusicSheet musicSheet = super.getById(id);
        if (YesOrNoEnum.YES.getCode().equals(musicSheet.getState().getCode())) {
            throw new BizException("启用状态下，不可删除");
        }
        musicSheet.setDelFlag(true);
        return this.updateById(musicSheet);
    }

    @Override
    public Integer countTeacherMusicSheet(SysUser sysUser) {
        return this.lambdaQuery()
                .eq(MusicSheet::getAuditStatus,AuthStatusEnum.PASS)
                .eq(MusicSheet::getCreateBy,sysUser.getId())
                .eq(MusicSheet::getState,YesOrNoEnum.YES)
                .eq(MusicSheet::getDelFlag,YesOrNoEnum.NO)
                .count();
    }

    @Override
    public boolean saveMusicSheet(MusicSheetDto musicSheetDto,Long userId) {

        if (musicSheetDto.getId() != null) {
            musicSheetAccompanimentService.delByMusicSheetId(musicSheetDto.getId());
        }

        List<MusicSheetAccompaniment> list;
        if (!AudioTypeEnum.MIDI.getCode().equals(musicSheetDto.getAudioType().getCode())){
            list = musicSheetDto.getBackground();
            if (CollectionUtils.isEmpty(list)){
                throw new BizException("mp3音频文件对应的主音或者伴奏文件没有提供");
            }
            return saveMp3AndAccompaniment(musicSheetDto,userId);
        } else {
            MusicSheet musicSheet = new MusicSheet();
            BeanUtils.copyProperties(musicSheetDto, musicSheet);
            musicSheet.setUpdateTime(new Date());
            musicSheet.setUpdateBy(userId);
            musicSheet.setState(YesOrNoEnum.NO);
            return this.saveOrUpdate(musicSheet);
        }
    }

    @Override
    public HttpResponseResult<OrderCreateRes> buyMusicSheetCheck(OrderReq.OrderReqInfo orderReqInfo) {

        // 下单前的验证
        getSysUser(orderReqInfo.getUserId());

        MusicSheetPayDto musicSheetPayDto = JSON.parseObject(
                JSON.toJSONString(orderReqInfo.getBizContent()), MusicSheetPayDto.class);

        MusicSheet musicSheet = this.getById(musicSheetPayDto.getMusicSheetId());
        OrderCreateRes orderCreateRes = new OrderCreateRes();
        if (musicSheet == null) {
            throw new BizException("不存在曲目信息");
        }

        // 检查已经购买
        checkoutPay(orderReqInfo.getUserId(),musicSheetPayDto.getMusicSheetId());



        orderCreateRes.setRes(true);
        orderCreateRes.setMerchId(musicSheet.getUserId());
        orderCreateRes.setGoodType(orderCreateRes.getGoodType());
        orderCreateRes.setBizId(musicSheet.getId());
        orderCreateRes.setGoodNum(1);
        orderCreateRes.setOriginalPrice(musicSheet.getMusicPrice());
        orderCreateRes.setExpectPrice(musicSheet.getMusicPrice());
        return  HttpResponseResult.succeed(orderCreateRes);

    }

    /**
     * 检查是否已购买当前曲目
     *
     * @param userId 用户id
     * @param musicSheetId 曲目id
     */
    private void checkoutPay(Long userId, Long musicSheetId) {
        List<MusicSheetPurchaseRecord> list = musicSheetPurchaseRecordService
                .lambdaQuery()
                .eq(MusicSheetPurchaseRecord::getMusicSheetId, musicSheetId)
                .eq(MusicSheetPurchaseRecord::getStudentId, userId)
                .eq(MusicSheetPurchaseRecord::getOrderStatus,OrderStatusEnum.PAID)
                .list();
        if (!CollectionUtils.isEmpty(list)) {
            throw  new BizException("已经购买了当前曲目");
        }
    }

    @Override
    @Transactional
    public void buyMusicSheetSuccess(UserOrderDetailVo userOrderDetailVo) {


        // 曲目服务费比例
        String musicSheetServiceFee= sysConfigService.findConfigValue(SysConfigConstant.MUSIC_SHEET_SERVICE_FEE);
        BigDecimal serviceFee = new BigDecimal(musicSheetServiceFee).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
        //支付金额
        BigDecimal actualPrice = userOrderDetailVo.getActualPrice();

        //服务费
        BigDecimal serviceFeeAmount = actualPrice.multiply(serviceFee).setScale(2, RoundingMode.HALF_UP);

        // 保存购买记录
        addMusicSheetPurchaseRecord(userOrderDetailVo, actualPrice, serviceFeeAmount);

        // 加入账户
        addTeacherAccount(userOrderDetailVo, actualPrice, serviceFeeAmount, userOrderDetailVo.getBizId());

        // 消息通知
        sendBuyMessage(userOrderDetailVo.getMerchId(),userOrderDetailVo.getUserId(),userOrderDetailVo.getBizId());
    }

    /**
     * 发送购买消息通知
     *
     * @param teacherId 老师id
     * @param studentId 学生id
     * @param musicSheetId 曲目id
     */
    @Override
    public boolean sendBuyMessage(Long teacherId, Long studentId, Long musicSheetId) {
        SysUser teacher = sysUserFeignService.queryUserById(teacherId);
        SysUser student = sysUserFeignService.queryUserById(studentId);
        if (StringUtil.isEmpty(teacher.getPhone())) {
            log.warn("teacher id {} name {} 手机号不存在，消息推送失败",teacher.getId(),teacher.getUsername());
        }

        MusicSheet musicSheet = this.getById(musicSheetId);
        // 推送老师
        Map<Long,String> teacherReceivers = new HashMap<>();
        teacherReceivers.put(teacherId, teacher.getPhone());

        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
                                           MessageTypeEnum.STUDENT_BUY_TEACHER_MUSIC_SHEET, teacherReceivers, null,
                                           0, null,ClientEnum.TEACHER.getCode(),student.getUsername(),musicSheet.getMusicSheetName());

        // 推送学生
        Map<Long,String> studentReceivers = new HashMap<>();
        studentReceivers.put(studentId, student.getPhone());

        // todo 乐谱连接
        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
                                           MessageTypeEnum.STUDENT_BUY_MUSIC_SHEET_SUCCESS, studentReceivers, null,
                                           0, null,ClientEnum.STUDENT.getCode(),musicSheet.getMusicSheetName(),"url");

        return true;
    }

    /**
     * 保存购买记录
     *
     * @param userOrderDetailVo 订单信息
     * @param actualPrice  付款价格
     * @param serviceFeeAmount 服务费
     */
    private void addMusicSheetPurchaseRecord(UserOrderDetailVo userOrderDetailVo, BigDecimal actualPrice, BigDecimal serviceFeeAmount) {
        MusicSheetPurchaseRecord musicSheetPurchaseRecord = musicSheetPurchaseRecordService
                .checkPurchase(userOrderDetailVo.getUserId(), userOrderDetailVo.getBizId());
        if (musicSheetPurchaseRecord == null) {
            musicSheetPurchaseRecord = new MusicSheetPurchaseRecord();
        }
        musicSheetPurchaseRecord.setMusicSheetId(userOrderDetailVo.getBizId());
        musicSheetPurchaseRecord.setOrderNo(userOrderDetailVo.getOrderNo());
        musicSheetPurchaseRecord.setPurchasePrice(actualPrice);
        musicSheetPurchaseRecord.setPurchaseTime(new Date());
        musicSheetPurchaseRecord.setTeacherId(userOrderDetailVo.getMerchId());
        musicSheetPurchaseRecord.setOriginalPrice(userOrderDetailVo.getOriginalPrice());
        musicSheetPurchaseRecord.setMusicSheetServiceFee(serviceFeeAmount);
        musicSheetPurchaseRecord.setOrderStatus(OrderStatusEnum.PAID);
        musicSheetPurchaseRecord.setStudentId(userOrderDetailVo.getUserId());
        musicSheetPurchaseRecordService.save(musicSheetPurchaseRecord);
    }

    /**
     * 添加金额到老师账户
     *
     * @param userOrderDetailVo 订单信息
     * @param actualPrice 付款价格
     * @param serviceFeeAmount 服务费
     * @param musicSheetId 曲目id
     */
    private void addTeacherAccount(UserOrderDetailVo userOrderDetailVo, BigDecimal actualPrice, BigDecimal serviceFeeAmount,
                                   Long musicSheetId) {
        UserAccountRecordDto userAccountRecordDto = new UserAccountRecordDto();
        userAccountRecordDto.setUserId(userOrderDetailVo.getMerchId());
        userAccountRecordDto.setFrozenType(FrozenTypeEnum.NONE);

        userAccountRecordDto.setTransAmount(actualPrice.subtract(serviceFeeAmount).setScale(2, RoundingMode.HALF_UP));
        userAccountRecordDto.setInOrOut(InOrOutEnum.IN);
        userAccountRecordDto.setBizType(AccountBizTypeEnum.MUSIC);
        userAccountRecordDto.setBizId(musicSheetId);
        userAccountRecordDto.setBizName(userOrderDetailVo.getGoodName());
        userAccountRecordDto.setOrderNo(userOrderDetailVo.getOrderNo());
        userAccountService.accountChange(userAccountRecordDto);
    }

    @Override
    public void orderAfterSheet(UserOrderDetailVo userOrderDetailVo) {
        // 保存购买记录
        MusicSheetPurchaseRecord musicSheetPurchaseRecord = musicSheetPurchaseRecordService
                .checkPurchase(userOrderDetailVo.getUserId(),userOrderDetailVo.getBizId());
        if (musicSheetPurchaseRecord == null) {
            musicSheetPurchaseRecord = new MusicSheetPurchaseRecord();
        }
        musicSheetPurchaseRecord.setMusicSheetId(userOrderDetailVo.getBizId());
        musicSheetPurchaseRecord.setOrderNo(userOrderDetailVo.getOrderNo());
        musicSheetPurchaseRecord.setTeacherId(userOrderDetailVo.getMerchId());
        musicSheetPurchaseRecord.setOriginalPrice(userOrderDetailVo.getOriginalPrice());
        musicSheetPurchaseRecord.setOrderStatus(OrderStatusEnum.WAIT_PAY);
        musicSheetPurchaseRecord.setStudentId(userOrderDetailVo.getUserId());
        musicSheetPurchaseRecordService.save(musicSheetPurchaseRecord);
    }

    @Override
    public void buyMusicSheetCancel(UserOrderDetailVo userOrderDetailVo) {
        MusicSheetPurchaseRecord musicSheetPurchaseRecord = musicSheetPurchaseRecordService
                .checkPurchase(userOrderDetailVo.getUserId(),userOrderDetailVo.getBizId());
        if (musicSheetPurchaseRecord == null) return;
        musicSheetPurchaseRecordService.removeById(musicSheetPurchaseRecord.getId());
    }

    private SysUser getSysUser(Long userId) {
        return Optional.ofNullable(userId)
                       .map(sysUserFeignService::queryUserById)
                       .orElseThrow(() -> new BizException("用户不存在"));
    }
}