package com.rf.psychological.scale.service.impl;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.Wildcard;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.rf.psychological.dao.dto.InstitutionRecordingDTO;
import com.rf.psychological.dao.dto.InstitutionRecordingUserDTO;
import com.rf.psychological.dao.dto.InstitutionRecordingUsersDTO;
import com.rf.psychological.dao.dto.UserRecordsDto;
import com.rf.psychological.dao.model.CognitiveTaskEntity;
import com.rf.psychological.enums.UserRole;
import com.rf.psychological.scale.dao.model.*;
import com.rf.psychological.scale.dao.repository.CognitiveTaskRepository;
import com.rf.psychological.scale.dao.repository.SubjectRepository;
import com.rf.psychological.scale.dao.repository.UserDeleteRepository;
import com.rf.psychological.scale.dao.repository.UserRecordRepository;
import com.rf.psychological.scale.service.UserRecordService;
import com.rf.psychological.user.dao.model.QUserEntity;
import com.rf.psychological.user.dao.model.UserEntity;
import com.rf.psychological.user.service.UserService;
import com.rf.psychological.utils.Constant;
import com.rf.psychological.utils.PageRequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zsy
 * @description:用户测试记录
 * @date 2021/6/17 15:55
 */
@Slf4j
@Service
public class UserRecordServiceImpl implements UserRecordService {

    @Autowired
    private UserRecordRepository userRecordRepository;

    @Autowired
    private UserDeleteRepository userDeleteRepository;

    @Autowired
    private JPAQueryFactory queryFactory;

    @Autowired
    private SubjectRepository subjectRepository;
    @Autowired
    private CognitiveTaskRepository cognitiveTaskRepository;

    @Autowired
    private UserService userService;


    /**
     * 保存
     *
     * @param userRecordEntity
     */
    @Override
    public void save(UserRecordEntity userRecordEntity) {
        this.userRecordRepository.save(userRecordEntity);
    }

    /**
     * 认知任务测试次数统计
     *
     * @return
     */
    @Override
    public List<UserRecordEntity> testAmount() {
        return this.userRecordRepository.testAmount();
    }

    /**
     * 根据手机号查询用户测试记录
     *
     * @return
     */
    @Override
    public List<UserRecordEntity> getTestListByPhone(int pageNum, int pageSize, String phone, String institutionNo, String searchKey) {
        int beginIndex = (pageNum - 1) * pageSize;
        return this.userRecordRepository.getTestListByPhone(beginIndex, pageSize, phone, institutionNo, searchKey);
    }

    @Override
    public Page<UserRecordsDto> getUserRecording(int pageNum, int pageSize, String phone, String institutionNo, String searchKey) {
//        Specification<UserRecordsDto> specification = (Specification<UserRecordsDto>) (root, query, cb) -> {
//            List<Predicate> predicateList = new ArrayList<>();
//            if(StringUtils.isNotEmpty(phone)){
//                predicateList.add(cb.equal(root.get("phone"),phone));
//            }
//            if(StringUtils.isNotEmpty(institutionNo)){
//                predicateList.add(cb.equal(root.get("institutionNo"),institutionNo));
//            }
//            if(StringUtils.isNotEmpty(searchKey)){
//                predicateList.add(cb.like(root.get("name"),"%"+searchKey+"%"));
//            }
//            query.where(cb.and(predicateList.toArray(new Predicate[0])));
//            query.orderBy(cb.desc(root.get("testDate")));
//            return query.getRestriction();
//        };
//        return  this.userRecordRepository.findAll(specification,PageRequest.of(pageNum-1,pageSize));
        QUserRecordEntity qUserRecordEntity = QUserRecordEntity.userRecordEntity;
        QUserEntity qUserEntity = QUserEntity.userEntity;
        QSubjectEntity qSubjectEntity = QSubjectEntity.subjectEntity;
        // 定于获取条件
        BooleanBuilder booleanBuilder = new BooleanBuilder();
        booleanBuilder.and(qUserRecordEntity.phone.eq(phone))
                .and(qUserEntity.institutionNo.eq(institutionNo));
        if (!StringUtils.isEmpty(searchKey)) {
            booleanBuilder.and(qUserRecordEntity.name.like("%" + searchKey + "%"));
        }
        booleanBuilder.and(qUserEntity.roleType.eq(UserRole.COMMON.getType()));
        List<UserRecordsDto> results = queryFactory.select(
                        Projections.bean(
                                UserRecordsDto.class,
                                qUserRecordEntity.id,
                                qUserRecordEntity.flag,
                                qUserRecordEntity.phone,
                                qUserRecordEntity.testDate,
                                qUserRecordEntity.fileName,
                                qUserRecordEntity.testResult,
                                qUserRecordEntity.type,
                                qUserRecordEntity.name,
                                qUserRecordEntity.img,
                                qUserRecordEntity.institutionNo,
                                qUserRecordEntity.testPlanId
                        )
                )
                .from(qUserRecordEntity)
                .leftJoin(qUserEntity)
                .on(
                        qUserRecordEntity.phone.eq(qUserEntity.phone)
                                .and(qUserRecordEntity.institutionNo.eq(qUserEntity.institutionNo))
                )
                .where(booleanBuilder)
                .orderBy(qUserRecordEntity.testDate.desc())
                .offset((long) (pageNum - 1) * pageSize)
                .limit(pageSize)
                .fetch();
        Map<String, List<UserRecordsDto>> records = results.stream().collect(Collectors.groupingBy(UserRecordsDto::getType));
        //获取认知任务的flag
        if (!CollectionUtils.isEmpty(records.get("1"))) {
            List<String> cognitiveFlag = records.get("1").stream().map(UserRecordsDto::getFlag).collect(Collectors.toList());
            List<CognitiveTaskEntity> cognitiveTaskEntities = cognitiveTaskRepository.findAllByTaskCode(cognitiveFlag);
            //将results中的量表或者认知任务id赋值
            results.stream().forEach(userRecordsDto -> cognitiveTaskEntities.forEach(cognitiveTask -> {
                if (userRecordsDto.getFlag().equals(cognitiveTask.getTaskCode())) {
                    userRecordsDto.setSubjectOrCognitiveId(cognitiveTask.getId());
                }
            }));
        }
        //获取量表flag
        if (!CollectionUtils.isEmpty(records.get("0"))) {
            List<String> subjectFlag = records.get("0").stream().map(UserRecordsDto::getFlag).collect(Collectors.toList());
            List<SubjectEntity> subjectEntityList = subjectRepository.findAllByFlag(subjectFlag);
            //将results中的量表或者认知任务id赋值
            results.stream().forEach(userRecordsDto -> {
                subjectEntityList.forEach(subjectEntity -> {
                    if (userRecordsDto.getFlag().equals(subjectEntity.getFlag())) {
                        userRecordsDto.setSubjectOrCognitiveId(subjectEntity.getId());
                    }
                });
            });
        }

        long count = queryFactory.select(Wildcard.count)
                .from(qUserRecordEntity)
                .join(qUserEntity)
                .on(
                        qUserRecordEntity.phone.eq(qUserEntity.phone)
                                .and(qUserRecordEntity.institutionNo.eq(qUserEntity.institutionNo))
                )
                .where(booleanBuilder)
                .orderBy(qUserRecordEntity.testDate.desc())
                .fetchCount();

        return new PageImpl<>(results, Pageable.unpaged(), count);
    }

    @Override
    public Page<UserRecordEntity> getUserRecording2(int pageNum, int pageSize, String phone, String institutionNo, String searchKey) {
        List<String> nos = new ArrayList<>();
        nos.add(phone);
        //处理该账号
        if (phone.length() == 11){
            UserEntity userEntity = userService.findByModelPhoneAndeInstitution(phone,institutionNo,Constant.DEFAULT_VALUE_ONE);
            if (userEntity != null){
                nos.add(userEntity.getPhone());
            }
        }else {
            UserEntity userEntity = userService.findPhoneAndInstitutionNoAndRoleType(phone,institutionNo, Constant.DEFAULT_VALUE_ONE);
            if (userEntity != null && StringUtils.isNotEmpty( userEntity.getModelPhone())){
                nos.add(userEntity.getModelPhone());
            }
        }

        Specification<UserRecordEntity> specification = (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();

            if(nos.size()>0){
                CriteriaBuilder.In<String> in = cb.in(root.get("phone"));
                for (String id : nos) {
                    in.value(id);
                }
                predicateList.add(in);
            }

//            if(StringUtils.isNotEmpty(phone)){
//                predicateList.add(cb.equal(root.get("phone"),phone));
//            }
            if(StringUtils.isNotEmpty(institutionNo)){
                predicateList.add(cb.equal(root.get("institutionNo"),institutionNo));
            }
            if(StringUtils.isNotEmpty(searchKey)){
                predicateList.add(cb.like(root.get("name"),"%"+searchKey+"%"));
            }
            query.where(cb.and(predicateList.toArray(new Predicate[0])));
            query.orderBy(cb.desc(root.get("testDate")));
            return query.getRestriction();
        };
        return  this.userRecordRepository.findAll(specification, PageRequestUtil.of(pageNum,pageSize));


    }

    @Override
    public List<UserRecordEntity> getListByPhoneAndTypeAndTime(int pageNum, int pageSize, String phone, String institutionNo, String type, String beginTime, String endTime) {
        int beginIndex = (pageNum - 1) * pageSize;
        return this.userRecordRepository.getListByPhoneAndTypeAndTime(beginIndex, pageSize, phone, institutionNo, type, beginTime, endTime);
    }

    @Override
    public int countByPhoneAndTypeAndTime(String phone, String type, String beginTime, String endTime, String institutionNo) {
        return this.userRecordRepository.countByPhoneAndTypeAndTime(phone, institutionNo, type, beginTime, endTime);
    }

    @Override
    public List<UserRecordEntity> getListByPhoneAndType(int pageNum, int pageSize, String phone, String institutionNo, String type) {
        int beginIndex = (pageNum - 1) * pageSize;
        return this.userRecordRepository.getListByPhoneAndType(beginIndex, pageSize, phone, institutionNo, type);
    }

    @Override
    public int countByPhoneAndType(String phone, String type, String institutionNo) {
        return this.userRecordRepository.countByPhoneAndType(phone, institutionNo, type);
    }

    /**
     * 根据手机号查询用户测试记录总条数
     *
     * @return
     */
    @Override
    public int allNumByPhone(String phone, String institutionNo, String searchKey) {
        return this.userRecordRepository.allNumByPhone(phone, institutionNo, searchKey);
    }

    /**
     * 根据id查询数据
     *
     * @return
     */
    @Override
    @Cacheable(value = "record", key = "#id",unless = "#result == null ")
    public UserRecordEntity getUserRecordById(String id) {
        return this.userRecordRepository.findUserRecordEntitiesById(id);
    }

    /**
     * 用户查询靶向神经振荡评估与训练记录
     *
     * @return
     */
    @Override
    public UserRecordEntity getRHYTHM(String phone, String institutionNo, String testPlanId) {
        return this.userRecordRepository.getRHYTHM(phone, institutionNo, testPlanId);
    }

    @Override
    public List<UserRecordEntity> getGUNSBULLETS(String phone, String institutionNo) {
        return this.userRecordRepository.getGUNSBULLETS(phone, institutionNo);
    }

    @Override
    public List<InstitutionRecordingDTO> getInstitutionUserRecording(int pageNum, int pageSize, String type, String institutionNo, String searchKey, String beginTime, String endTime) {
        int beginIndex = (pageNum - 1) * pageSize;
        return this.userRecordRepository.getInstitutionUserRecording(beginIndex, pageSize, institutionNo, type, searchKey, beginTime, endTime);

    }


    @Override
    public int allCountByInstitutionNo(String institutionNo, String type, String searchKey, String beginTime, String endTime) {
        return this.userRecordRepository.allCountByInstitutionNo(institutionNo, type, searchKey, beginTime, endTime);

    }

    @Override
    public List<InstitutionRecordingUserDTO> getInstitutionRecording(int pageNum, int pageSize, String institutionNo, String name, String searchKey, String beginFormat, String endFormat, String groupId) {
        Pageable pageRequest = PageRequest.of(pageNum - 1, pageSize);
        return this.userRecordRepository.getInstitutionRecording(pageRequest, institutionNo, name, searchKey, beginFormat, endFormat, groupId);
    }

    @Override
    public int allCountInstitutionRecording(String institutionNo, String name, String searchKey, String beginFormat, String endFormat, String groupId) {
        return this.userRecordRepository.allCountInstitutionRecording(institutionNo, name, searchKey, beginFormat, endFormat, groupId);
    }

    /**
     * 查询全量数据
     *
     * @return
     */
    @Override
    public List<UserRecordEntity> findAll() {
        return this.userRecordRepository.findAll();
    }

    /**
     * 根据id修改信息
     *
     * @param
     * @return
     */
    @Override
    public void updateById(String id, String testResult) {
        this.userRecordRepository.updateById(id, testResult);
    }

    @Override
    public List<InstitutionRecordingUsersDTO> getInstitution(String institutionNo, String name, String searchName, String beginTime, String endTime, String groupId) {
        if (beginTime.equals("") && endTime.equals("")) {
            return this.userRecordRepository.getInstitution(institutionNo, name, searchName, groupId);
        } else {
            String beginFormat = "", endFormat = "";
            log.info("开始时间：" + beginTime);
            log.info("结束时间：" + endTime);
            try {
                if (!beginTime.equals("") && !endTime.equals("")) {
                    beginTime = beginTime + " " + "00:00:00";
                    endTime = endTime + " " + "23:59:59";
                    //格式化为数据库的时间样式
                    SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
                    Date beginDate = simpleDateFormat1.parse(beginTime);
                    Date endDate = simpleDateFormat1.parse(endTime);

                    beginFormat = simpleDateFormat2.format(beginDate);
                    endFormat = simpleDateFormat2.format(endDate);
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            log.info("格式化后为beginFormat:" + beginFormat);
            log.info("格式化后为endFormat:" + endFormat);
            return this.userRecordRepository.getInstitution(institutionNo, name, searchName, beginFormat, endFormat, groupId);
        }

    }

    @Override
    public List<UserRecordEntity> getRecordingInfoByTestPlanIdAndPhoneAndInstitutionNoAndType(String institutionNo, String testPlanId, String phone, String type) {
        return userRecordRepository.findAllByInstitutionNoAndTestPlanIdAndPhoneAndType(institutionNo, testPlanId, phone, type);
    }

    @Override
    public List<UserRecordEntity> findAll1() {
        return this.userRecordRepository.findAll1();
    }

    @Override
    public UserRecordEntity findByPhoneAndTestPlanIdAndInstitution(String institutionNo, String phone, String testPlanId, String flag) {
        UserRecordEntity userRecordEntity = this.userRecordRepository.findByPhoneAndTestPlanIdAndInstitution(institutionNo, phone, testPlanId, flag);
        /*UserRecordEntity userRecordEntity = new UserRecordEntity();
        userRecordEntity.setPhone(phone);
        userRecordEntity.setInstitutionNo(institutionNo);
        userRecordEntity.setTestPlanId(testPlanId);
        userRecordEntity.setFlag(flag);
        Optional<UserRecordEntity> userRecordRepositoryOne = userRecordRepository.findOne(Example.of(userRecordEntity));
        return userRecordRepositoryOne.orElse(null);*/
        return userRecordEntity;
    }

    @Override
    public List<UserRecordEntity> getUserRecordByPlanId(String testPlanId) {
        return this.userRecordRepository.getUserRecordByPlanId(testPlanId);
    }

    @Override
    public List<UserRecordEntity> getuserRecordByPhone(String phone,String flag) {
        return this.userRecordRepository.getuserRecordByPhone(phone,flag);
    }

    @Override
    public InstitutionRecordingUsersDTO getRecordingUsersDTOById(String id) {
        return this.userRecordRepository.getRecordingUsersDTOById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatchByInstitution(String institutionNo) {
        UserRecordEntity userRecordEntity = new UserRecordEntity();
        userRecordEntity.setInstitutionNo(institutionNo);
        List<UserRecordEntity> userRecords = this.userRecordRepository.findAll(Example.of(userRecordEntity));
        //将测试记录转移到删除表
        List<UserDeleteRecordEntity> userDeleteRecordEntities = userRecords.stream().map(item -> {
            UserDeleteRecordEntity userDeleteRecordEntity = new UserDeleteRecordEntity();
            BeanUtils.copyProperties(item, userDeleteRecordEntity);
            userDeleteRecordEntity.setDeleteTime(LocalDateTime.now());
            return userDeleteRecordEntity;
        }).collect(Collectors.toList());
        userDeleteRepository.saveAll(userDeleteRecordEntities);
        //删除测试记录
        this.userRecordRepository.deleteAllByInstitutionNo(institutionNo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAllByPhoneAndInstitutionNo(String phone, String institutionNo) {
        UserRecordEntity userRecordEntity = new UserRecordEntity();
        userRecordEntity.setPhone(phone);
        userRecordEntity.setInstitutionNo(institutionNo);
        //查询当前用户下的测试记录
        List<UserRecordEntity> userRecords = userRecordRepository.findAll(Example.of(userRecordEntity));
        //将测试记录转移到删除表
        List<UserDeleteRecordEntity> userDeleteRecordEntities = userRecords.stream().map(item -> {
            UserDeleteRecordEntity userDeleteRecordEntity = new UserDeleteRecordEntity();
            BeanUtils.copyProperties(item, userDeleteRecordEntity);
            userDeleteRecordEntity.setDeleteTime(LocalDateTime.now());
            return userDeleteRecordEntity;
        }).collect(Collectors.toList());
        userDeleteRepository.saveAll(userDeleteRecordEntities);
        //删除测试记录
        this.userRecordRepository.deleteAllByPhoneAndInstitutionNo(phone, institutionNo);
    }

    @Override
    public UserRecordEntity getuserRecordByIdAndInstitutionNoAndPhone(String resultId, String userId, String institutionNo) {
        return this.userRecordRepository.getuserRecordByIdAndInstitutionNoAndPhone(resultId,userId,institutionNo);
    }

    /**
     * 历史记录
     * @param pageNum
     * @param pageSize
     * @param phone
     * @param institutionNo
     * @param flag
     * @return
     */
    @Override
    public Page<UserRecordEntity> getHistoryRecord(int pageNum, int pageSize, String phone, String institutionNo, String flag) {
        Specification specification =  getRecord(phone, institutionNo, flag);
        Page<UserRecordEntity> page = userRecordRepository.findAll(specification,PageRequestUtil.of(pageNum,pageSize));

        return page;
    }

    @Override
    public int countHistoryRecord(String phone, String institutionNo, String flag) {
        Specification specification = getRecord(phone, institutionNo, flag);
        List<UserRecordEntity> list = userRecordRepository.findAll(specification);
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)){
            return 0;
        }else {
            return list.size();
        }
    }

    @Override
    public int finAllByInstitutionNo(String institutionNo) {
        return userRecordRepository.findAllByInstitutionNo(institutionNo);
    }

    @Override
    public String findByTestNum(String institutionNo,int i) {
        return userRecordRepository.findByTestNum(institutionNo,i);
    }

    /**
     * 微博分享-通过手机号查询测试记录
     * @param pageNum
     * @param pageSize
     * @param modelPhone
     * @return
     */
    @Override
    public Page<UserRecordEntity> getRecordByModelPhone(int pageNum, int pageSize, String modelPhone, String orderStatus) {
        return userRecordRepository.getRecordByModelPhone(modelPhone, orderStatus, PageRequest.of(pageNum - 1, pageSize));
    }

    @Override
    public int countNum(String flag, String promotionStartTime) {
        return userRecordRepository.countAllByFlagAndTestDateGreaterThanEqual(flag,promotionStartTime);
    }

    private Specification getRecord(String phone, String institutionNo, String flag) {
        String dateEnd = DateUtil.format(DateUtil.offsetDay(new Date(),1), DatePattern.CHINESE_DATE_FORMAT);
        String dateBegin = DateUtil.format(DateUtil.offsetDay(new Date(),-90),DatePattern.CHINESE_DATE_FORMAT);
        Specification specification = ((root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (StringUtils.isNotEmpty(phone)){
                list.add(criteriaBuilder.equal(root.get("phone"),phone));
            }
            if (StringUtils.isNotEmpty(institutionNo)){
                list.add(criteriaBuilder.equal(root.get("institutionNo"),institutionNo));
            }

            if (StringUtils.isNotEmpty(flag)){
                list.add(criteriaBuilder.equal(root.get("flag"),flag));
            }
            list.add(criteriaBuilder.between(root.get("testDate"),dateBegin,dateEnd));
            query.where(criteriaBuilder.and(list.toArray(new Predicate[list.size()])));
            query.orderBy(criteriaBuilder.desc(root.get("testDate")));
            return query.getRestriction();
        });
        return specification;
    }




}
