package com.keao.edu.user.service.impl;


import com.keao.edu.auth.api.client.SysUserFeignService;
import com.keao.edu.auth.api.entity.SysUser;
import com.keao.edu.common.dal.BaseDAO;
import com.keao.edu.common.entity.SysConfig;
import com.keao.edu.common.enums.MessageTypeEnum;
import com.keao.edu.common.exception.BizException;
import com.keao.edu.common.page.PageInfo;
import com.keao.edu.common.page.QueryInfo;
import com.keao.edu.common.service.IdGeneratorService;
import com.keao.edu.common.service.SysMessageService;
import com.keao.edu.common.service.impl.BaseServiceImpl;
import com.keao.edu.thirdparty.message.provider.JiguangPushPlugin;
import com.keao.edu.thirdparty.message.provider.YimeiSmsPlugin;
import com.keao.edu.user.dao.*;
import com.keao.edu.user.dto.*;
import com.keao.edu.user.entity.*;
import com.keao.edu.user.enums.ExamStatusEnum;
import com.keao.edu.user.enums.StudentRegistrationStatusEnum;
import com.keao.edu.user.enums.TransStatusEnum;
import com.keao.edu.user.page.ApplyListQueryInfo;
import com.keao.edu.user.page.ExamRecordQueryInfo;
import com.keao.edu.user.page.ExamRegistrationQueryInfo;
import com.keao.edu.user.service.*;
import com.keao.edu.util.collection.MapUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class ExamRegistrationServiceImpl extends BaseServiceImpl<Long, ExamRegistration> implements ExamRegistrationService {

    @Autowired
    private ExamRegistrationDao examRegistrationDao;
    @Autowired
    private ExaminationBasicDao examinationBasicDao;
    @Autowired
    private OrganizationService organizationService;
    @Autowired
    private PayService payService;
    @Autowired
    private ExamSubjectSongDao examSubjectSongDao;
    @Autowired
    private ExamMusicTheoryDao examMusicTheoryDao;
    @Autowired
    private IdGeneratorService idGeneratorService;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private ExamRegistrationPaymentService examRegistrationPaymentService;
    @Autowired
    private OrganizationDao organizationDao;
    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private SysConfigService sysConfigService;

    @Override
    public BaseDAO<Long, ExamRegistration> getDAO() {
        return examRegistrationDao;
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public Map<String, Object> addRegistration(ExamRegistration examRegistration) throws Exception {
        ExaminationBasic examinationBasic = examinationBasicDao.lockExam(examRegistration.getExaminationBasicId());
        if (examinationBasic == null || !examinationBasic.getStatus().equals(ExamStatusEnum.APPLYING)) {
            throw new BizException("项目不在报名中，请核对");
        }

        //考试级别信息
        ExamSubjectSong examSubjectSong = examSubjectSongDao.get(examRegistration.getExamSubjectSongId());
        if (examSubjectSong == null) {
            throw new BizException("请选择专业级别");
        }

        if (examRegistration.getOrganId() == null) {
            throw new BizException("机构id不能为空");
        }
        Organization organization = organizationDao.get(examRegistration.getOrganId());
        if (organization == null) {
            throw new BizException("机构不存在");
        }

        List<StudentRegistrationStatusEnum> statusEnumList = new ArrayList<>();
        statusEnumList.add(StudentRegistrationStatusEnum.AUDIT_WAIT);
        statusEnumList.add(StudentRegistrationStatusEnum.AUDIT_REJECT);
        statusEnumList.add(StudentRegistrationStatusEnum.AUDIT_PASS);
        statusEnumList.add(StudentRegistrationStatusEnum.PAY_WAIT);

        ExamRegistration registration = examRegistrationDao.getRegistration(examinationBasic.getId(),
                examRegistration.getStudentId(), examRegistration.getSubjectId(), examSubjectSong.getLevel(),
                statusEnumList);
        if (registration != null) {
            throw new BizException("该考级相同专业及等级您已报名，请勿重复报名");
        }

        Date nowDate = new Date();
        String orderNo = idGeneratorService.generatorId("payment") + "";

        examRegistration.setLevel(examSubjectSong.getLevel());
        BigDecimal amount = examSubjectSong.getRegistrationFee();
        //乐理考试级别
        ExamMusicTheory examMusicTheory = null;
        BigDecimal theoryLevelFee = BigDecimal.ZERO;
        if (examRegistration.getExamMusicTheoryId() != null) {
            examMusicTheory = examMusicTheoryDao.get(examRegistration.getExamMusicTheoryId());
        }
        if (examMusicTheory != null) {
            theoryLevelFee = examMusicTheory.getFee();
            examRegistration.setExamMusicTheoryLevel(examMusicTheory.getLevel());
            amount = amount.add(theoryLevelFee);
        }

        examRegistration.setTenantId(organization.getTenantId());
        examRegistration.setStatus(StudentRegistrationStatusEnum.PAY_WAIT);
        examRegistration.setLevelFee(examSubjectSong.getRegistrationFee());
        examRegistration.setTheoryLevelFee(theoryLevelFee);
        examRegistration.setCreateTime(nowDate);
        examRegistration.setUpdateTime(nowDate);
        examRegistrationDao.insert(examRegistration);

        ExamRegistrationPayment examRegistrationPayment = new ExamRegistrationPayment();
        examRegistrationPayment.setTenantId(examinationBasic.getTenantId());
        examRegistrationPayment.setOrganId(examRegistration.getOrganId());
        examRegistrationPayment.setExamRegistrationId(examRegistration.getId().longValue());
        examRegistrationPayment.setStudentId(examRegistration.getStudentId());
        examRegistrationPayment.setExaminationBasicId(examRegistration.getExaminationBasicId());
        examRegistrationPayment.setOrderNo(orderNo);
        examRegistrationPayment.setTransAmount(amount);
        examRegistrationPayment.setTransStatus(TransStatusEnum.ING);
        examRegistrationPayment.setCreateTime(nowDate);
        examRegistrationPayment.setUpdateTime(nowDate);
        examRegistrationPaymentService.insert(examRegistrationPayment);

        HashMap<String, Object> rpMap = new HashMap<>();
        String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");
        Map<String, Object> payMap = payService.getPayMap(
                amount,
                orderNo,
                baseApiUrl + "/api-user/examOrder/notify",
                baseApiUrl + "/api-user/examOrder/paymentResult?orderNo=" + orderNo,
                examinationBasic.getName(),
                examinationBasic.getName()
        );
        examRegistrationPayment.setMerNo((String) payMap.get("routingMerNos"));
        examRegistrationPayment.setPayType((String) payMap.get("type"));
        examRegistrationPaymentService.update(examRegistrationPayment);
        rpMap.put("examRegister", examRegistration);
        rpMap.put("payMap", payMap);
        return rpMap;
    }

    @Override
    public PageInfo<ExamRegistrationRoomDto> queryExamRegistrationStudents(ExamRegistrationQueryInfo queryInfo) {
        PageInfo<ExamRegistrationRoomDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<String, Object>();
        MapUtil.populateMap(params, queryInfo);

        if (Objects.nonNull(queryInfo.getExamId())) {
            List<Integer> nextLevelOrganIds = organizationService.getChildOrganIds(queryInfo.getOrganId(), true);
            params.put("organIds", nextLevelOrganIds);
            params.put("organId", null);
        }

        List<ExamRegistrationRoomDto> dataList = Collections.EMPTY_LIST;
        int count = examRegistrationDao.countExamRegist(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = examRegistrationDao.queryExamRegist(params);
            List<Long> examIds = dataList.stream().filter(e -> Objects.nonNull(e.getOrganId())).map(ExamRegistration::getExaminationBasicId).collect(Collectors.toList());
            Map<Long, String> examIdNameMap = this.getMap("examination_basic", "id_", "name_", examIds, Long.class, String.class);

            List<Integer> organIds = dataList.stream().filter(e -> Objects.nonNull(e.getOrganId())).map(ExamRegistration::getOrganId).collect(Collectors.toList());
            Map<Integer, String> organIdNameMap = this.getMap("organization", "id_", "name_", organIds, Integer.class, String.class);

            List<Integer> subjectIds = dataList.stream().map(ExamRegistration::getSubjectId).collect(Collectors.toList());
            Map<Integer, String> subjectIdNameMap = this.getMap("subject", "id_", "name_", subjectIds, Integer.class, String.class);

            List<Integer> studentIds = dataList.stream().map(ExamRegistration::getStudentId).collect(Collectors.toList());
            Map<Integer, String> idPhotoMap = this.getMap("student", "user_id_", "certificate_photo_", studentIds, Integer.class, String.class);

            List<Integer> registIds = dataList.stream().map(ExamRegistrationRoomDto::getId).collect(Collectors.toList());
            Map<Integer, Integer> registExamStatusMap = this.getMap("student_exam_result", "exam_registration_id_", "is_finished_exam_", registIds, Integer.class, Integer.class);

            for (ExamRegistrationRoomDto examRegistration : dataList) {
                examRegistration.setOrganization(new Organization(examRegistration.getOrganId(), organIdNameMap.get(examRegistration.getOrganId())));
                examRegistration.getSubject().setName(subjectIdNameMap.get(examRegistration.getSubjectId()));
                examRegistration.getSysUser().setCertificatePhoto(idPhotoMap.get(examRegistration.getStudentId()));
                examRegistration.setIsFinishedExam(Objects.isNull(registExamStatusMap.get(examRegistration.getId()))?3:registExamStatusMap.get(examRegistration.getId()));
                examRegistration.setExaminationBasic(new ExaminationBasic(examRegistration.getExaminationBasicId(), examIdNameMap.get(examRegistration.getExaminationBasicId())));
            }
        }

        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public ExamRegistrationStatisticsDto getExamRegistrationStaticsInfo(Integer organId, Integer examId) {
        List<Integer> childOrganIds = organizationService.getChildOrganIds(organId, true);
        ExamRegistrationStatisticsDto examRegistrationStaticsInfo = examRegistrationDao.getExamRegistrationStaticsInfo(organId, childOrganIds, examId);
        if (Objects.isNull(examRegistrationStaticsInfo)) {
            examRegistrationStaticsInfo = new ExamRegistrationStatisticsDto();
        }
        return examRegistrationStaticsInfo;
    }

    @Override
    public PageInfo<ExamRegistrationDto> applyList(ApplyListQueryInfo queryInfo) {
        PageInfo<ExamRegistrationDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<String, Object>();
        MapUtil.populateMap(params, queryInfo);
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        params.put("studentId",sysUser.getId());

        List<ExamRegistrationDto> dataList = null;
        int count = examRegistrationDao.countStudentList(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = examRegistrationDao.queryStudentList(params);
            List<Integer> subjectIds = dataList.stream().map(e -> e.getSubjectId()).collect(Collectors.toList());
            Map<Integer, String> subjectNameMap = this.getMap("subject", "id_", "name_", subjectIds, Integer.class, String.class);
            dataList.forEach(e -> {
                e.setSubjectName(subjectNameMap.get(e.getSubjectId()));
            });
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public PageInfo<StudentExamListDto> examList(ExamRecordQueryInfo queryInfo) {
        PageInfo<StudentExamListDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<String, Object>();
        MapUtil.populateMap(params, queryInfo);

        List<StudentExamListDto> dataList = null;
        int count = examRegistrationDao.countExamList(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = examRegistrationDao.queryExamList(params);
            List<Integer> subjectIds = dataList.stream().map(e -> e.getSubjectId()).collect(Collectors.toList());
            Map<Integer, String> subjectNameMap = this.getMap("subject", "id_", "name_", subjectIds, Integer.class, String.class);
            dataList.forEach(e -> {
                e.setSubjectName(subjectNameMap.get(e.getSubjectId()));
            });
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public void updateExamRegistrationStatus(Long registId, StudentRegistrationStatusEnum status, String memo) {
        if (Objects.isNull(registId)) {
            throw new BizException("请指定学员报名信息");
        }
        ExamRegistration er = examRegistrationDao.get(registId);
        if (Objects.isNull(er)) {
            throw new BizException("学员报名信息不存在");
        }
        if (!StudentRegistrationStatusEnum.AUDIT_WAIT.equals(er.getStatus())) {
            throw new BizException("审核状态错误");
        }
        if (!StudentRegistrationStatusEnum.AUDIT_PASS.equals(status)
                && !StudentRegistrationStatusEnum.AUDIT_REJECT.equals(status)) {
            throw new BizException("审核状态错误");
        }
        er.setStatus(status);
        er.setMemo(memo);

        SysConfig baseUrlConfig = sysConfigService.findByParamName(SysConfigService.BASE_H5_URL);
        String baseUrl="";
        if(Objects.nonNull(baseUrlConfig)){
            baseUrl=baseUrlConfig.getParanValue();
        }
        baseUrl = "1?" + baseUrl+"/#/appDetail?id=" + registId;

        Map<Integer, String> receiverMap = new HashMap<>(1);
        receiverMap.put(er.getStudentId(), er.getStudentId().toString());
        if(StudentRegistrationStatusEnum.AUDIT_PASS.equals(er.getStatus())){
            sysMessageService.batchSendMessage(MessageTypeEnum.REGIST_PASS_PUSH,
                    receiverMap, null, 0, null, JiguangPushPlugin.PLUGIN_NAME);
        }else if(StudentRegistrationStatusEnum.AUDIT_REJECT.equals(er.getStatus())){
            sysMessageService.batchSendMessage(MessageTypeEnum.REGIST_REJECT_PUSH,
                    receiverMap, null, 0, baseUrl, JiguangPushPlugin.PLUGIN_NAME);

            SysUser student = sysUserDao.get(er.getStudentId());
            Map<Integer, String> phoneMap = new HashMap<>(1);
            phoneMap.put(er.getStudentId(), student.getPhone());
            sysMessageService.batchSendMessage(MessageTypeEnum.REGIST_REJECT_SMS,
                    phoneMap, null, 0, null, YimeiSmsPlugin.PLUGIN_NAME);
        }
        examRegistrationDao.update(er);
    }

    @Override
    public void updateExamRegistration(ExamRegistration examRegistration) {
        if (Objects.isNull(examRegistration.getId())) {
            throw new BizException("学员报名信息有误");
        }
        ExamRegistration er = examRegistrationDao.get(examRegistration.getId().longValue());
        if (Objects.isNull(er)) {
            throw new BizException("学员报名信息有误");
        }
        if(er.getStudentId().equals(examRegistration.getStudentId())){
            examRegistration.setStatus(StudentRegistrationStatusEnum.AUDIT_WAIT);
        }else{
            examRegistration.setStatus(null);
        }
        examRegistrationDao.update(examRegistration);
    }

    @Override
    public ExamRegistrationDto getExamRegistration(Long examRegistrationId) {
        return examRegistrationDao.getExamRegistration(examRegistrationId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> repay(Integer userId, String orderNo) throws Exception {
        ExamRegistrationPayment order = examRegistrationPaymentService.getByOrderNo(orderNo);
        if (!order.getTransStatus().equals(TransStatusEnum.ING)) {
            throw new BizException("订单不是待支付状态,请重新报名");
        }
        Date nowDate = new Date();
        order.setTransStatus(TransStatusEnum.CLOSE);
        order.setUpdateTime(nowDate);
        examRegistrationPaymentService.update(order);

        orderNo = idGeneratorService.generatorId("payment") + "";

        order.setId(null);
        order.setTransNo(null);
        order.setCreateTime(nowDate);
        order.setTransStatus(TransStatusEnum.ING);
        order.setOrderNo(orderNo);
        examRegistrationPaymentService.insert(order);

        ExaminationBasic examinationBasic = examinationBasicDao.get(order.getExaminationBasicId());
        if (examinationBasic == null || !examinationBasic.getStatus().equals(ExamStatusEnum.APPLYING)) {
            throw new BizException("项目不在报名中，请核对");
        }
        Map<String, Object> rpMap = new HashMap<>();
        String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");
        Map<String, Object> payMap = payService.getPayMap(
                order.getTransAmount(),
                orderNo,
                baseApiUrl + "/api-user/examOrder/notify",
                baseApiUrl + "/api-user/examOrder/paymentResult?orderNo=" + orderNo,
                examinationBasic.getName(),
                examinationBasic.getName()
        );
        order.setMerNo((String) payMap.get("routingMerNos"));
        order.setPayType((String) payMap.get("type"));
        examRegistrationPaymentService.update(order);
        ExamRegistration examRegistration = examRegistrationDao.get(order.getExamRegistrationId());
        rpMap.put("examRegister", examRegistration);
        rpMap.put("payMap", payMap);
        return rpMap;
    }

    @Override
    public PageInfo<StudentBaseExamsDto> studentBaseExams(QueryInfo queryInfo) {
        PageInfo<StudentBaseExamsDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        params.put("studentId",sysUser.getId());
        List<StudentBaseExamsDto> dataList = null;
        params.put("paymentStatus",1);
        int count = examRegistrationDao.countStudentBaseExams(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = examRegistrationDao.queryStudentBaseExams(params);
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }
}
