package com.xinelu.applet.service.nurseappletpersontraining.impl;


import com.xinelu.applet.mapper.trainingitemwatchrecord.TrainingItemWatchRecordMapper;
import com.xinelu.applet.mapper.trainingorderdetails.TrainingOrderDetailsMapper;
import com.xinelu.applet.service.nurseappletpersontraining.NurseAppletPersonTrainingService;
import com.xinelu.common.constant.Constants;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.common.enums.*;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.StringUtils;
import com.xinelu.common.utils.bean.BeanUtils;
import com.xinelu.manage.domain.trainingitemplayrecord.TrainingItemPlayRecord;
import com.xinelu.manage.domain.trainingitemwatchrecord.TrainingItemWatchRecord;
import com.xinelu.manage.domain.trainingorder.TrainingOrder;
import com.xinelu.manage.domain.trainingorderdetails.TrainingOrderDetails;
import com.xinelu.manage.domain.trainingorderitemdirectory.TrainingOrderItemDirectory;
import com.xinelu.manage.dto.trainingitem.NurseAppletPersonTrainingItemDTO;
import com.xinelu.manage.dto.trainingitem.TrainingItemDTO;
import com.xinelu.manage.dto.trainingitemwatchrecord.TrainingItemWatchRecordDTO;
import com.xinelu.manage.dto.trainingorder.NurseAppletPersonTrainingItemOrderDTO;
import com.xinelu.manage.mapper.information.InformationMapper;
import com.xinelu.manage.mapper.trainingitem.TrainingItemMapper;
import com.xinelu.manage.mapper.trainingitemplayrecord.TrainingItemPlayRecordMapper;
import com.xinelu.manage.mapper.trainingorder.TrainingOrderMapper;
import com.xinelu.manage.mapper.trainingorderitemdirectory.TrainingOrderItemDirectoryMapper;
import com.xinelu.manage.vo.trainingitem.NurseAppletPersonTrainingItemVO;
import com.xinelu.manage.vo.trainingitem.TrainingItemVO;
import com.xinelu.manage.vo.trainingitemdirectory.TrainingItemDirectoryVO;
import com.xinelu.manage.vo.trainingorderdetails.NurseAppletPersonTrainingOrderDetailsVO;
import com.xinelu.manage.vo.trainingorderdetails.TrainingDetailsByOrderVO;
import com.xinelu.manage.vo.trainingorderitemdirectory.TrainingOrderItemDirectoryInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 护理员学习培训
 *
 * @author ljh
 * @version 1.0
 * Create by 2023/4/21 9:01
 */
@Slf4j
@Service
public class NurseAppletPersonTrainingServiceImpl implements NurseAppletPersonTrainingService {
    @Resource
    private TrainingItemMapper trainingItemMapper;
    @Resource
    private TrainingOrderMapper trainingOrderMapper;
    @Resource
    private TrainingOrderDetailsMapper trainingOrderDetailsMapper;
    @Resource
    private TrainingOrderItemDirectoryMapper trainingOrderItemDirectoryMapper;
    @Resource
    private TrainingItemWatchRecordMapper trainingItemWatchRecordMapper;
    @Resource
    private InformationMapper informationMapper;
    @Resource
    private TrainingItemPlayRecordMapper trainingItemPlayRecordMapper;

    /**
     * 不能购买标识
     */
    private static final Integer NOT_BUY_FLAG = 1;

    /**
     * 学习培训-查询学习培训课程组信息
     *
     * @param trainingItem 学习培训项目信息
     * @return 学习培训项目信息集合
     */
    @Override
    public List<TrainingItemVO> getTrainingItemGroupInfo(TrainingItemDTO trainingItem) {
        if (Objects.isNull(trainingItem) || Objects.isNull(trainingItem.getNurseStationPersonId())) {
            return Lists.newArrayList();
        }
        trainingItem.setTrainingParentId(Constants.TRAINING_PARENT_ID);
        trainingItem.setTrainingShelfFlag(TrainingShelfFlagEnum.SHEL.getInfo());
        trainingItem.setTrainingOrderStatus(TrainingOrderStatusEnum.PAY.getInfo());
        trainingItem.setTrainingItemType(TrainingItemTypeEnum.GRAPHIC_LEARNING.getInfo());
        return trainingItemMapper.getTrainingItemList(trainingItem);
    }

    /**
     * 学习培训-查询查询学习培训课程下属视频和图文信息
     *
     * @param trainingItem 学习培训项目信息
     * @return 学习培训项目信息集合
     */
    @Override
    public AjaxResult getTrainingVideoAndContentList(TrainingItemDTO trainingItem) {
        trainingItem.setTrainingOrderStatus(TrainingOrderStatusEnum.PAY.getInfo());
        return AjaxResult.success(trainingItemMapper.getTrainingItemList(trainingItem));
    }

    /**
     * 学习培训-查询学习培训课程详情信息
     *
     * @param trainingItem 学习培训项目信息
     * @return 学习培训项目信息集合
     */
    @Override
    public AjaxResult getTrainingItemDetailsInfo(NurseAppletPersonTrainingItemDTO trainingItem) {
        trainingItem.setTrainingOrderStatus(TrainingOrderStatusEnum.PAY.getInfo());
        NurseAppletPersonTrainingItemVO nurseAppletPersonTrainingItemVO = trainingItemMapper.selectTrainingLearnItemDetailsList(trainingItem);
        if ((Objects.isNull(nurseAppletPersonTrainingItemVO))) {
            return AjaxResult.success();
        }
        if (CollectionUtils.isEmpty(nurseAppletPersonTrainingItemVO.getTrainingItemDirectoryList())) {
            return AjaxResult.success(nurseAppletPersonTrainingItemVO);
        }
        //查询订单表中的数据
        List<TrainingItemDirectoryVO> trainingItemDirectoryList = nurseAppletPersonTrainingItemVO.getTrainingItemDirectoryList();
        List<Long> trainingItemDirectoryIdList = trainingItemDirectoryList.stream().filter(Objects::nonNull).filter(training -> Objects.nonNull(training.getTrainingItemDirectoryId())).map(TrainingItemDirectoryVO::getTrainingItemDirectoryId).collect(Collectors.toList());
        List<TrainingOrderItemDirectoryInfoVO> trainingOrderItemDirectoryList = trainingOrderItemDirectoryMapper.getTrainingOrderItemDirectoryList(trainingItem.getNurseStationPersonId(), nurseAppletPersonTrainingItemVO.getTrainingItemId(), trainingItemDirectoryIdList, TrainingOrderStatusEnum.PAY.getInfo());
        if (CollectionUtils.isEmpty(trainingOrderItemDirectoryList)) {
            return AjaxResult.success(nurseAppletPersonTrainingItemVO);
        }
        Map<Long, TrainingOrderItemDirectoryInfoVO> trainingMap = trainingOrderItemDirectoryList.stream().filter(Objects::nonNull).filter(training -> (Objects.nonNull(training.getTrainingItemDirectoryId()))).collect(Collectors.toMap(TrainingOrderItemDirectoryInfoVO::getTrainingItemDirectoryId, item -> item));
        for (TrainingItemDirectoryVO trainingItemDirectoryVO : trainingItemDirectoryList) {
            if (Objects.isNull(trainingItemDirectoryVO) || Objects.isNull(trainingItemDirectoryVO.getTrainingItemDirectoryId())) {
                continue;
            }
            TrainingOrderItemDirectoryInfoVO directory = trainingMap.getOrDefault(trainingItemDirectoryVO.getTrainingItemDirectoryId(), null);
            if (Objects.isNull(directory)) {
                continue;
            }
            trainingItemDirectoryVO.setNurseStationId(Objects.isNull(directory.getNurseStationId()) ? null : directory.getNurseStationId());
            trainingItemDirectoryVO.setNurseStationPersonId(Objects.isNull(directory.getNurseStationPersonId()) ? null : directory.getNurseStationPersonId());
            trainingItemDirectoryVO.setNursePersonName(StringUtils.isBlank(directory.getNursePersonName()) ? "" : directory.getNursePersonName());
            trainingItemDirectoryVO.setTrainingOrderId(Objects.isNull(directory.getTrainingOrderId()) ? null : directory.getTrainingOrderId());
            trainingItemDirectoryVO.setTrainingOrderNo(StringUtils.isBlank(directory.getTrainingOrderNo()) ? "" : directory.getTrainingOrderNo());
            trainingItemDirectoryVO.setItemDirectoryWatchStatus(StringUtils.isBlank(directory.getItemDirectoryWatchStatus()) ? "" : directory.getItemDirectoryWatchStatus());
            trainingItemDirectoryVO.setTrainingOrderStatus(StringUtils.isBlank(directory.getTrainingOrderStatus()) ? "" : directory.getTrainingOrderStatus());
            trainingItemDirectoryVO.setWatchTime(Objects.isNull(directory.getWatchTime()) ? null : directory.getWatchTime());
        }
        return AjaxResult.success(nurseAppletPersonTrainingItemVO);
    }

    /**
     * 学习培训-下单方法（App和小程序共用）
     *
     * @param trainingItemOrderDTO 培训订单
     * @return com.xinyilu.common.core.domain.AjaxResult
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult buyTrainingItemOrder(NurseAppletPersonTrainingItemOrderDTO trainingItemOrderDTO) {
        trainingItemOrderDTO.setTrainingParentId(trainingItemOrderDTO.getTrainingItemId());
        List<NurseAppletPersonTrainingItemVO> nurseAppletPersonTrainingItemList = trainingItemMapper.selectTrainingLearnItemList(trainingItemOrderDTO);
        if (CollectionUtils.isEmpty(nurseAppletPersonTrainingItemList)) {
            return AjaxResult.error("当前培训课程不存在，无法下单，请联系管理员！");
        }
        NurseAppletPersonTrainingItemVO trainingItemVO = nurseAppletPersonTrainingItemList.stream().filter(Objects::nonNull)
                .filter(item -> Objects.nonNull(item.getTrainingItemId()) &&
                        trainingItemOrderDTO.getTrainingItemId().equals(item.getTrainingItemId())).findFirst().orElse(null);
        if (Objects.isNull(trainingItemVO)) {
            return AjaxResult.error("当前培训课程不存在或无法下单，请联系管理员！");
        }
        if (Objects.isNull(trainingItemVO.getBuyFlag()) || NOT_BUY_FLAG.equals(trainingItemVO.getBuyFlag())) {
            return AjaxResult.error("当前培训课程不能购买，无法下单，请联系管理员！");
        }
        List<String> trainingOrderStatusList = Arrays.asList(TrainingOrderStatusEnum.PAY.getInfo(), TrainingOrderStatusEnum.WAIT_PAY.getInfo());
        int trainingOrderCount = trainingOrderDetailsMapper.getBuyTrainingOrderInfo(trainingItemOrderDTO.getTrainingItemId(), trainingItemOrderDTO.getNurseStationPersonId(), trainingOrderStatusList);
        if (trainingOrderCount > 0) {
            return AjaxResult.error("当前培训课程已购买或者已下单，如果已下单请前往我的学习订单页面支付购买！");
        }
        //新增培训订单主对象
        TrainingOrder trainingOrder = new TrainingOrder();
        String trainingOrderNo = StringUtils.fillZeroByPatientId(trainingItemOrderDTO.getNurseStationPersonId(), 5) + System.nanoTime();
        trainingOrder.setNurseStationId(trainingItemOrderDTO.getNurseStationId());
        trainingOrder.setNurseStationPersonId(trainingItemOrderDTO.getNurseStationPersonId());
        trainingOrder.setNursePersonName(StringUtils.isBlank(trainingItemOrderDTO.getNursePersonName()) ? "" : trainingItemOrderDTO.getNursePersonName());
        String trainingOrderStatus = trainingItemOrderDTO.getTrainingOrderAmount().compareTo(BigDecimal.ZERO) == 0 ? TrainingOrderStatusEnum.PAY.getInfo() : TrainingOrderStatusEnum.WAIT_PAY.getInfo();
        trainingOrder.setTrainingOrderStatus(trainingOrderStatus);
        trainingOrder.setTrainingOrderAmount(trainingItemOrderDTO.getTrainingOrderAmount());
        trainingOrder.setTrainingOrderChannel(TrainingOrderChannelEnum.WECHAT_APPLET.getInfo());
        trainingOrder.setTrainingOrderNo(trainingOrderNo);
        trainingOrder.setTrainingOrderTime(LocalDateTime.now());
        trainingOrder.setDelFlag(0);
        trainingOrder.setCreateBy(StringUtils.isBlank(trainingItemOrderDTO.getNursePersonName()) ? "" : trainingItemOrderDTO.getNursePersonName());
        trainingOrder.setCreateTime(LocalDateTime.now());
        int insertTrainingOrder = trainingOrderMapper.insertTrainingOrder(trainingOrder);
        if (insertTrainingOrder <= 0) {
            log.error("新增培训订单信息失败");
            throw new ServiceException("购买学习培训课程下单失败，请联系管理员！");
        }
        //新增订单明细表
        for (NurseAppletPersonTrainingItemVO trainingItem : nurseAppletPersonTrainingItemList) {
            this.addTrainingOrderDetailsInfo(trainingItemOrderDTO, trainingOrder, trainingItem, trainingOrderNo);
        }
        TrainingOrder selectTrainingOrderById = trainingOrderMapper.selectTrainingOrderById(trainingOrder.getId());
        return AjaxResult.success(selectTrainingOrderById);
    }

    /**
     * 我的学习-查询已购买学习培训项目详情
     *
     * @param trainingItem 学习培训项目信息
     * @return 学习培训项目信息集合
     */
    @Override
    public AjaxResult selectTrainingOrderVideoDetails(NurseAppletPersonTrainingItemDTO trainingItem) {
        return AjaxResult.success(trainingOrderMapper.selectTrainingOrderVideoDetailsList(trainingItem));
    }

    /**
     * 我的学习-查询学习培训项目订单集合组
     *
     * @param trainingItem 学习培训项目
     * @return java.util.List<com.xinyilu.base.vo.trainingitem.NurseAppletPersonTrainingItemVO>
     **/
    @Override
    public List<NurseAppletPersonTrainingOrderDetailsVO> selectTrainingOrderItemGroupList(NurseAppletPersonTrainingItemDTO trainingItem) {
        if (Objects.isNull(trainingItem) || Objects.isNull(trainingItem.getNurseStationPersonId())) {
            return Lists.newArrayList();
        }
        trainingItem.setTrainingParentId(Constants.TRAINING_PARENT_ID);
        trainingItem.setTrainingItemType(TrainingItemTypeEnum.GRAPHIC_LEARNING.getInfo());
        return trainingOrderMapper.selectTrainingOrderVideoList(trainingItem);
    }

    /**
     * 我的学习-查询学习培训项目订单集合
     *
     * @param trainingItem 学习培训项目
     * @return java.util.List<com.xinyilu.base.vo.trainingitem.NurseAppletPersonTrainingItemVO>
     **/
    @Override
    public AjaxResult selectTrainingOrderItemList(NurseAppletPersonTrainingItemDTO trainingItem) {
        return AjaxResult.success(trainingOrderMapper.selectTrainingOrderVideoList(trainingItem));
    }

    /**
     * 查询学习培训课程观看时间点记录信息（观看视频用，App和小程序共用）
     *
     * @param trainingItemWatchRecord 学习培训项目观看时间点记录信息
     * @return java.util.List<com.xinyilu.base.domain.trainingcategory.TrainingCategory>
     **/
    @Override
    public AjaxResult getTrainingWatchRecord(TrainingItemWatchRecord trainingItemWatchRecord) {
        return AjaxResult.success(trainingItemWatchRecordMapper.getTrainingItemWatchRecordById(trainingItemWatchRecord));
    }

    /**
     * 学习培训项目观看时间点记录信息（退出视频用）
     *
     * @param trainingItemWatchRecord 学习培训项目
     * @return java.util.List<com.xinyilu.base.domain.trainingcategory.TrainingCategory>
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult insertTrainingWatchRecord(TrainingItemWatchRecordDTO trainingItemWatchRecord) {
        TrainingDetailsByOrderVO trainingDetailsByOrderVO = trainingOrderDetailsMapper.selectTrainingOrderDetailsByOrderId(trainingItemWatchRecord.getTrainingOrderId());
        if (Objects.isNull(trainingDetailsByOrderVO)) {
            return AjaxResult.error("视频播放失败，请联系管理员！");
        }
        TrainingItemWatchRecord trainingItemWatchRecordById = trainingItemWatchRecordMapper.getTrainingItemWatchRecordById(trainingItemWatchRecord);
        if (Objects.isNull(trainingItemWatchRecordById)) {
            trainingItemWatchRecord.setWatchDate(LocalDate.now());
            trainingItemWatchRecord.setTrainingItemDirectoryName(StringUtils.isBlank(trainingItemWatchRecord.getItemDirectoryName()) ? "" : trainingItemWatchRecord.getItemDirectoryName());
            trainingItemWatchRecord.setCreateTime(LocalDateTime.now());
            int itemWatchRecord = trainingItemWatchRecordMapper.insertTrainingItemWatchRecord(trainingItemWatchRecord);
            if (itemWatchRecord <= 0) {
                throw new ServiceException("视频播放失败，请联系管理员！");
            }
            String orderNo = StringUtils.isBlank(trainingDetailsByOrderVO.getTrainingOrderNo()) ? "" : trainingDetailsByOrderVO.getTrainingOrderNo();
            int orderItemDirectory = trainingOrderItemDirectoryMapper.updatePersonTrainingOrderItemDirectory(trainingItemWatchRecord.getTrainingItemDirectoryId(), orderNo, ItemDirectoryWatchStatusEnum.WATCHED.getInfo());
            if (orderItemDirectory <= 0) {
                throw new ServiceException("视频播放失败，请联系管理员！");
            }
            //新增学习培训项目播放日志记录表
            this.addTrainingItemPlayRecord(trainingItemWatchRecord);
            return AjaxResult.success();
        }
        trainingItemWatchRecord.setWatchDate(LocalDate.now());
        trainingItemWatchRecord.setId(trainingItemWatchRecordById.getId());
        trainingItemWatchRecord.setUpdateTime(LocalDateTime.now());
        int itemWatchRecord = trainingItemWatchRecordMapper.updateTrainingItemWatchRecord(trainingItemWatchRecord);
        if (itemWatchRecord <= 0) {
            throw new ServiceException("视频播放失败，请联系管理员！");
        }
        //修改章节视频观看状态
        String itemDirectoryWatchStatus = trainingItemWatchRecord.getWatchTime().equals(trainingItemWatchRecord.getItemDirectoryVideoDuration()) ? ItemDirectoryWatchStatusEnum.FINISHED_READING.getInfo() : ItemDirectoryWatchStatusEnum.WATCHED.getInfo();
        int orderItemDirectory = trainingOrderItemDirectoryMapper.updatePersonTrainingOrderItemDirectory(trainingItemWatchRecord.getTrainingItemDirectoryId(), trainingDetailsByOrderVO.getTrainingOrderNo(), itemDirectoryWatchStatus);
        if (orderItemDirectory <= 0) {
            throw new ServiceException("视频退出失败，请联系管理员！");
        }
        //新增学习培训项目播放日志记录表
        this.addTrainingItemPlayRecord(trainingItemWatchRecord);
        return AjaxResult.success();
    }

    /**
     * 查询待支付的订单详情信息
     *
     * @param trainingOrderNo 学习培训订单编号
     * @return 详情信息
     */
    @Override
    public AjaxResult getWaitPayTrainingOrderDetails(String trainingOrderNo) {
        return AjaxResult.success(trainingOrderDetailsMapper.getWaitPayTrainingOrderDetailsInfo(trainingOrderNo, TrainingOrderStatusEnum.WAIT_PAY.getInfo()));
    }

    /**
     * 新增订单表
     *
     * @param trainingItemOrderDTO 前端传的培训订单信息
     * @param trainingOrder        培训订单信息
     * @param trainingItem         培训项目信息
     * @param trainingOrderNo      订单编号
     **/
    private void addTrainingOrderDetailsInfo(NurseAppletPersonTrainingItemOrderDTO trainingItemOrderDTO, TrainingOrder trainingOrder,
                                             NurseAppletPersonTrainingItemVO trainingItem, String trainingOrderNo) {
        //新增学习培训订单明细对象
        TrainingOrderDetails trainingOrderDetails = new TrainingOrderDetails();
        BeanUtils.copyProperties(trainingItem, trainingOrderDetails);
        trainingOrderDetails.setTrainingOrderId(trainingOrder.getId());
        trainingOrderDetails.setTrainingOrderNo(trainingOrderNo);
        trainingOrderDetails.setDelFlag(0);
        trainingOrderDetails.setCreateBy(StringUtils.isBlank(trainingItemOrderDTO.getNursePersonName()) ? "" : trainingItemOrderDTO.getNursePersonName());
        trainingOrderDetails.setCreateTime(LocalDateTime.now());
        int insertTrainingOrderDetails = trainingOrderDetailsMapper.insertTrainingOrderDetails(trainingOrderDetails);
        if (insertTrainingOrderDetails <= 0) {
            log.error("新增学习培训订单明细信息失败，请联系管理员！");
            throw new ServiceException("购买学习培训课程下单失败，请联系管理员！");
        }
        if (CollectionUtils.isEmpty(trainingItem.getTrainingItemDirectoryList())) {
            return;
        }
        //新增学习培训订单明细章节，记录视频学习和直播课程的章节信息对象
        List<TrainingOrderItemDirectory> trainingOrderItemDirectoryList = Lists.newArrayList();
        for (TrainingItemDirectoryVO trainingItemDirectory : trainingItem.getTrainingItemDirectoryList()) {
            TrainingOrderItemDirectory trainingOrderItemDirectory = new TrainingOrderItemDirectory();
            BeanUtils.copyProperties(trainingItemDirectory, trainingOrderItemDirectory);
            trainingOrderItemDirectory.setTrainingOrderDetailsId(trainingOrderDetails.getId());
            trainingOrderItemDirectory.setTrainingOrderNo(trainingOrderNo);
            trainingOrderItemDirectory.setTrainingItemDirectoryId(trainingItemDirectory.getTrainingItemDirectoryId());
            trainingOrderItemDirectory.setItemDirectoryWatchStatus(ItemDirectoryWatchStatusEnum.NOT_WATCHED.getInfo());
            trainingOrderItemDirectory.setCreateBy(StringUtils.isBlank(trainingItemOrderDTO.getNursePersonName()) ? "" : trainingItemOrderDTO.getNursePersonName());
            trainingOrderItemDirectory.setCreateTime(LocalDateTime.now());
            trainingOrderItemDirectoryList.add(trainingOrderItemDirectory);
        }
        int insertTrainingOrderItemDirectory = trainingOrderItemDirectoryMapper.insertTrainingOrderItemDirectoryList(trainingOrderItemDirectoryList);
        if (insertTrainingOrderItemDirectory <= 0) {
            log.error("新增学习培训订单明细章节信息失败");
            throw new ServiceException("购买学习培训课程下单失败，请联系管理员！");
        }
    }

    /**
     * 新增学习培训项目播放日志记录表
     *
     * @param trainingItemWatchRecord 学习培训项目
     * @date 2023/5/5 13:53
     **/
    private void addTrainingItemPlayRecord(TrainingItemWatchRecordDTO trainingItemWatchRecord) {
        TrainingItemPlayRecord trainingItemPlayRecord = new TrainingItemPlayRecord();
        BeanUtils.copyProperties(trainingItemWatchRecord, trainingItemPlayRecord);
        trainingItemPlayRecord.setTrainingItemDirectoryName(trainingItemWatchRecord.getItemDirectoryName());
        trainingItemPlayRecord.setPlayTime(LocalDateTime.now());
        trainingItemPlayRecord.setPlayDate(LocalDate.now());
        trainingItemPlayRecord.setCreateTime(LocalDateTime.now());
        int itemPlayRecord = trainingItemPlayRecordMapper.insertTrainingItemPlayRecord(trainingItemPlayRecord);
        if (itemPlayRecord <= 0) {
            throw new ServiceException("视频播放失败，请联系管理员！");
        }
    }

}
