package com.yizhi.application.project.controller;

import com.baomidou.mybatisplus.plugins.Page;
import com.yizhi.application.project.controller.util.ProjectWorkUtil;
import com.yizhi.application.tools.PageTools;
import com.yizhi.core.application.cache.RedisCache;
import com.yizhi.core.application.context.ContextHolder;
import com.yizhi.core.application.context.RequestContext;
import com.yizhi.course.application.feign.*;
import com.yizhi.course.application.vo.OfflineCourseStudentVo;
import com.yizhi.enroll.application.feign.EnrollFeignClient;
import com.yizhi.enroll.application.vo.GetEnrollVO;
import com.yizhi.live.application.feign.LiveActivityClient;
import com.yizhi.live.application.vo.LiveActivityVO;
import com.yizhi.site.application.enums.FunctionTypeCode;
import com.yizhi.site.application.feign.api.FunctionDisplayConfigApiClients;
import com.yizhi.site.application.vo.domain.FunctionDisplayConfigVo;
import com.yizhi.system.application.system.remote.AccountClient;
import com.yizhi.system.application.vo.AccountVO;
import com.yizhi.training.application.constant.ProjectConstant;
import com.yizhi.training.application.feign.*;
import com.yizhi.training.application.model.BaseModel;
import com.yizhi.training.application.vo.api.*;
import com.yizhi.util.application.domain.Response;
import com.yizhi.util.application.enums.i18n.Constants;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

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

@Api(tags = "培训项目PC端接口")
@RestController
@RequestMapping("/pc/trainingProject")
public class PcTrainingProjectController {
    private static final Logger LOGGER = LoggerFactory.getLogger(PcTrainingProjectController.class);

    @Autowired
    private TrainingProjectClient trainingProjectClient;
    @Autowired
    private EnrollFeignClient enrollFeignClient;

    @Autowired
    private TpPlanActivityClient tpPlanActivityClient;
    @Autowired
    TpCommentClient tpCommentClient;
    @Autowired
    TpCommentReplyClient tpCommentReplyClient;
    @Autowired
    TpCommentThumbsUpClient tpCommentThumbsUpClient;
    @Autowired
    CourseClient courseClient;
    @Autowired
    CoursePcClient coursePcClient;
    @Autowired
    CommClient commClient;
    @Autowired
    CommentClient commentClient;
    @Autowired
    GradeClient gradeClient;
    @Autowired
    private OfflineCourseClient offlineCourseClient;
    @Autowired
    TpEnrollPassedClient tpEnrollPassedClient;
    @Autowired
    AccountClient accountClient;
    @Autowired
    RecordeClient recordeClient;
    @Autowired
    private FunctionDisplayConfigApiClients configApiClients;
    @Autowired
    private ProjectWorkUtil workUtil;


    @Autowired
    RedisCache redisCache;

    @Autowired
    LiveActivityClient liveActivityClient;


    /**
     * PC端火热报名列表
     *
     * @param vo
     * @return
     */
    @ApiOperation(value = "PC端火热报名列表")
    @PostMapping("/pc/hot/page/list")
    public Response<Page<HotEnrollListVo>> pcHotPageList(
            @ApiParam(value = "火热报名列表参数", required = true) @RequestBody HotEnrollParamVo vo) {
        BaseModel<HotEnrollParamVo> model = new BaseModel<>();
        model.setContext(ContextHolder.get());
        model.setDate(new Date());
        model.setObj(vo);
        Page<HotEnrollListVo> resultPage = trainingProjectClient.pcHotPageList(model);
        List<HotEnrollListVo> listVos = resultPage.getRecords();
        List<FunctionDisplayConfigVo> dataFunction = configApiClients.getAllBySiteId();
        Boolean trainingDurationShow = false;
        if (!CollectionUtils.isEmpty(dataFunction)) {
            for (FunctionDisplayConfigVo a : dataFunction) {
                if (FunctionTypeCode.TRAINING.getCode().equals(a.getFunctionType())) {
                    trainingDurationShow = a.getShowDisplay();

                }
            }
        }
        if (!CollectionUtils.isEmpty(listVos)) {
            for (HotEnrollListVo tr : listVos) {
                List<Long> listCourseIds = tr.getListCourseIds();
                tr.setPeriod(0f);
                tr.setTrainingDurationShow(trainingDurationShow);
                if (!CollectionUtils.isEmpty(listCourseIds)) {
                    Float allMaterialTime = 0f;

                    Map<Long, Float> map = coursePcClient.getStudyHourByCourseIds(listCourseIds);
                    if (null != map) {
                        for (Long courseId : listCourseIds) {
                            Float materialTime = map.get(courseId);
                            allMaterialTime = (null == materialTime ? 0 : materialTime) + allMaterialTime;
                            tr.setPeriod(allMaterialTime);
                        }
                    }
                }
            }
        }
        Map<String, Integer> pageMap = new HashMap<>();
        pageMap.put("pageNo", resultPage.getCurrent());
        pageMap.put("pageSize", resultPage.getSize());
        pageMap.put("pageTotal", resultPage.getPages());
        return Response.ok(resultPage, pageMap);

    }


    /**
     * PC端分页列表 -- 培训项目首页
     *
     * @param vo
     * @return
     */
    @PostMapping("/pc/page/list")
    @ApiOperation(value = "培训项目首页列表")
    public Response<Page<TrainingProjectListVo>> pcPageList(
            @ApiParam(value = "PC端培训项目列表查询参数vo", required = true) @RequestBody TrainingProjectParamVo vo) {

        RequestContext context = ContextHolder.get();

        BaseModel<TrainingProjectParamVo> model = new BaseModel<>();
        model.setContext(context);
        model.setDate(new Date());
        model.setObj(vo);
        Page<TrainingProjectListVo> resultPage = trainingProjectClient.pcPageList(model);
        List<TrainingProjectListVo> listVos = resultPage.getRecords();
        List<FunctionDisplayConfigVo> dataFunction = configApiClients.getAllBySiteId();

        Boolean trainingDurationShow = false;
        if (!CollectionUtils.isEmpty(dataFunction)) {
            for (FunctionDisplayConfigVo a : dataFunction) {
                if (FunctionTypeCode.TRAINING.getCode().equals(a.getFunctionType())) {
                    trainingDurationShow = a.getShowDisplay();
                }
            }
        }
        if (!CollectionUtils.isEmpty(listVos)) {
            for (TrainingProjectListVo tr : listVos) {
                List<Long> listCourseIds = tr.getListCourseIds();
                tr.setPeriod(0f);
                tr.setTrainingDurationShow(trainingDurationShow);
                if (!CollectionUtils.isEmpty(listCourseIds)) {
                    Float allMaterialTime = 0f;
                    Map<Long, Float> map = coursePcClient.getStudyHourByCourseIds(listCourseIds);
                    if (null != map) {
                        for (Long courseId : listCourseIds) {
                            Float materialTime = map.get(courseId);
                            allMaterialTime = (null == materialTime ? 0 : materialTime) + allMaterialTime;
                            tr.setPeriod(allMaterialTime);
                        }
                    }
                }
            }
        }
        Map<String, Integer> pageMap = new HashMap<>();
        pageMap.put("pageNo", resultPage.getCurrent());
        pageMap.put("pageSize", resultPage.getSize());
        pageMap.put("pageTotal", resultPage.getPages());
        return Response.ok(resultPage, pageMap);

    }

    /**
     * 分页列表 -- Pc端我的培训项目
     *
     * @param trainingProjectMyParamVo
     * @return
     */
    @PostMapping("/pc/page/my/list")
    @ApiOperation(value = "Pc端我的培训项目")
    public Response<TrainingProjectListVo> pcMyPageList(@ApiParam(value = "trainingProjectMyParamVo") @RequestBody TrainingProjectMyParamVo trainingProjectMyParamVo) {

        RequestContext context = ContextHolder.get();
        BaseModel model = new BaseModel();
        model.setContext(context);
        model.setDate(new Date());
        model.setObj(trainingProjectMyParamVo);
        Page<TrainingProjectListVo> resultPage = trainingProjectClient.apiMyPageList(model);
        Pair pair = PageTools.split(resultPage);
        return Response.ok(resultPage, (Map<String, Integer>) pair.getRight());

    }


    @PostMapping("/pc/tpPlanActivity/view/record/add")
    @ApiOperation(value = "(PC端)培训活动浏览记录")
    public Response addViewRecord(
            @ApiParam(value = "培训项目活动id，格式：{\"id\": 123}", required = true) @RequestBody IdVo idVo) {
        try {
            if (null == idVo.getId()) {
                return Response.fail(Constants.MSG_REQUEST_ERROR);
            }
            BaseModel<Long> baseModel = new BaseModel<>();
            baseModel.setDate(new Date());
            baseModel.setContext(ContextHolder.get());
            baseModel.setObj(idVo.getId());
            return Response.ok(tpPlanActivityClient.addViewRecord(baseModel));
        } catch (Exception e) {
            LOGGER.error("", e);
            return Response.fail(Constants.MSG_BIZ_FAIL.getCode().toString(), Constants.MSG_BIZ_FAIL.getName());
        }
    }

    @PostMapping("/pc/certificate/grant")
    @ApiOperation(value = "(PC端)点击发放证书")
    public Response<String> grantCertificate(
            @ApiParam("参数：{\"certificateId\" : \"111\", \"planId\": \"111\"}") @RequestBody Map<String, Long> param) {
        try {
            Long certificateId = param.get("certificateId");
            Long planId = param.get("planId");

            if (null == certificateId || certificateId.equals(0L) || null == planId || planId.equals(0L)) {
                return Response.fail(Constants.MSG_REQUEST_ERROR);
            }
            RequestContext context = ContextHolder.get();

            param.put("companyId", context.getCompanyId());
            param.put("siteId", context.getSiteId());
            param.put("accountId", context.getAccountId());

            Constants status = tpPlanActivityClient.certificatePcGrant(param);

            return Response.ok(status.getName());
        } catch (Exception e) {
            LOGGER.error("", e);
            return Response.fail(Constants.MSG_BIZ_FAIL.getCode().toString(), Constants.MSG_BIZ_FAIL.getName());
        }
    }

    @GetMapping("/offlineCourse/get")
    @ApiOperation(value = "PC端线下课程查看(培训项目内容_线下课程)", notes = "查看操作", response = OfflineCourseStudentVo.class)
    public Response get(
            @ApiParam(name = "id", value = "课程接受参数对象(线下课程id)") @RequestParam(name = "id") Long id
    ) {
        OfflineCourseStudentVo courseVo = offlineCourseClient.getList(id);
        return Response.ok(courseVo);
    }


    @PostMapping("/pc/one/detail/progress/view")
    @ApiOperation(value = "(PC端)培训详情，带学习记录", response = TrainingProjectDetailVo.class)
    public Response<TrainingProjectDetailVo> getTpDetailWithProgressed(@ApiParam(value = "培训项目id，格式：{\"id\": 123}", required = true) @RequestBody IdVo idVo) {
        try {
            BaseModel<Long> model = new BaseModel<>();
            model.setObj(idVo.getId());
            model.setDate(new Date());
            RequestContext context = ContextHolder.get();
            model.setContext(context);
            Long accountId = context.getAccountId();
            Long siteId = context.getSiteId();
            TrainingProjectDetailVo vo = trainingProjectClient.getPcTpDetailWithProgress(model);
            Long currentTime = System.currentTimeMillis();

            // 如果查询到培训项目
            if (null != vo) {
                TrainingProjectIntroductionVo introductionVo = vo.getIntroductionVo();
                //判断报名项目的人数限制类型,判断名额已满时需要
                if (introductionVo.getType() == ProjectConstant.PROJECT_VISIBLE_RANGE_SITE) {
                    //报名项目为平台可见，培训名额取所属站点人数，否则取指定人员
                    introductionVo = projectIsVisibleSite(introductionVo);
                }

                if (introductionVo.getNeedEnroll()) {
                    //需要报名
                    Response.ok(needEnroll(introductionVo, currentTime));

                } else {
                    //不需要报名
                    Response.ok(judgeTime(introductionVo, currentTime));

                }
                // 查询直播频道号需要
                List<TrainingProjectContentPlanVo> dataList = vo.getContentVo().getPlans();
                Integer minPoint = 0;
                Integer maxPoint = 0;

                //组装其直播频道 ，顺便计算积分
                //暂时不计算活动积分
                Boolean enabled = false;
                Map map = workUtil.buildMap(dataList, introductionVo, enabled);
                if (map != null) {
                    dataList = (List<TrainingProjectContentPlanVo>) map.get("dataList");
                    if (enabled) {
                        minPoint = workUtil.returnNumber(map.get("minPoint"));
                        maxPoint = workUtil.returnNumber(map.get("maxPoint"));
                    }
                }
                introductionVo.setEnablePoint(introductionVo.getPoint() <= 0 ? false : true);
                introductionVo.setMaxPoint(maxPoint);
                introductionVo.setMinPoint(minPoint);
            }

            // 查询直播的观看权限类型
            List<TrainingProjectContentPlanVo> dataAll = vo.getContentVo().getPlans();
            if(! CollectionUtils.isEmpty(dataAll)){
                for(TrainingProjectContentPlanVo item : dataAll){
                    List<TrainingProjectContentActivityVo> inData = item.getActivities();
                    List<Long> filterData = inData.parallelStream().filter(filterItem ->
                            Integer.valueOf(3).equals(filterItem.getType())).map(dataItem-> dataItem.getRelationId()).collect(Collectors.toList());
                    if(filterData != null){
                        Page<LiveActivityVO> liveData = liveActivityClient.LiveActivityByIds(filterData,0,filterData.size());
                        Map<Long,Integer> dataMap = liveData.getRecords().stream().
                                collect(Collectors.toMap(key->key.getId(),val->val.getViewType()));
                        for(TrainingProjectContentActivityVo itemTmp :  inData){
                            if(Integer.valueOf(3).equals(itemTmp.getType()) && dataMap.containsKey(itemTmp.getRelationId())){
                                itemTmp.setViewType(dataMap.get(itemTmp.getRelationId()));
                            }
                        }
                    }
                }
            }
            return Response.ok(vo);

        } catch (Exception e) {
            LOGGER.error("", e);
            return Response.fail(Constants.MSG_BIZ_FAIL.getCode().toString(), Constants.MSG_BIZ_FAIL.getName());
        }
    }


    /**
     * 报名项目为平台可见，培训名额取所属站点人数,如果是指定学员，在后台执行
     *
     * @param introductionVo 培训信息表
     * @return
     */
    private TrainingProjectIntroductionVo projectIsVisibleSite(TrainingProjectIntroductionVo introductionVo) {
        List<AccountVO> accountVOS = accountClient.findBySiteId(ContextHolder.get().getSiteId());
//        List list = new ArrayList();
//        list.add(introductionVo.getId());
//        List<TrainningEnrollVO> enrollPassedVos = enrollFeignClient.selectTrainningEnroll(list);
        //去重
        Set<AccountVO> accountVOSet = new HashSet<>();
//        Set<TrainningEnrollVO> enrollPassedVosSet = new HashSet<>();
        accountVOSet.addAll(accountVOS);
//        enrollPassedVosSet.addAll(enrollPassedVos);
        //培训名额 为所属站点下所有人
        Integer enrollLimit = accountVOSet.size();
        //已参与人数 报名通过表的记录
//        Integer hasEnrolledNum = enrollPassedVosSet.size();
//        introductionVo.setHasEnrolledNum(hasEnrolledNum);
        introductionVo.setTrMembers(enrollLimit);

        return introductionVo;

    }

    /**
     * 需要报名
     *
     * @param introductionVo 培训信息表
     * @param currentTime    当前时间
     * @return
     */
    private Response needEnroll(TrainingProjectIntroductionVo introductionVo, Long currentTime) {

        //查询报名信息
        GetEnrollVO enroll = enrollFeignClient.pcGetEnrollByProjectId(introductionVo.getId(), ContextHolder.get().getAccountId());

        if (enroll != null) {
            TrainingProjectIntroductionEnrollVo enrollVo = new TrainingProjectIntroductionEnrollVo();
            enrollVo.setId(enroll.getId());
            enrollVo.setStartTime(enroll.getStartTime());
            enrollVo.setEndTime(enroll.getEndTime());
            enrollVo.setLimit(enroll.getLimit());
            enrollVo.setNotice(enroll.getNotice());
            introductionVo.setEnroll(enrollVo);
            introductionVo.setEnrollLimit(enroll.getLimit());
            introductionVo.setHasEnrolled(enroll.getHasEnrolled());
            introductionVo.setNeedAudit(enroll.getNeedAudit());
            introductionVo.setHasEnrolledNum(enroll.getHasEnrolledNum());
            //是否付费
            introductionVo.setEnablePay(enroll.getEnablePay());
            introductionVo.setActualPrice(enroll.getActualPrice());
            introductionVo.setOriginalPrice(enroll.getOriginalPrice());
            //据此判断报名项目的人数报名类型 false--无限制 、true--有限制
            Boolean hasLimitNums = enroll.getHasLimitNums();

            //判断是否有报名记录
            introductionVo = whetherHasEnrollRecord(introductionVo, enroll, currentTime, hasLimitNums);

        } else {
            return Response.fail(Constants.TRAINING_MSG_PROJECT_NOT_EXiST.getCode().toString(), Constants.TRAINING_MSG_PROJECT_NOT_EXiST.getName());
        }
        return Response.ok(introductionVo);
    }

    /**
     * 判断是否有报名记录
     *
     * @param introductionVo
     * @param enroll
     * @param currentTime
     * @param hasLimitNums
     * @return
     */
    private TrainingProjectIntroductionVo whetherHasEnrollRecord(TrainingProjectIntroductionVo introductionVo, GetEnrollVO enroll, Long currentTime, Boolean hasLimitNums) {
        if (introductionVo.getHasEnrolled()) {
            //是否需要审核
            introductionVo = whetherNeedAudit(introductionVo, enroll, currentTime);

        } else {
            //需要报名且没有报名，根据当前时间，判断能否报名
            introductionVo = jugdeEnrollStatus(introductionVo, enroll, currentTime, hasLimitNums);
        }

        return introductionVo;
    }

    /**
     * 已经报名，判断是否需要审核
     *
     * @param introductionVo
     * @param enroll
     * @param currentTime
     * @return
     */
    private TrainingProjectIntroductionVo whetherNeedAudit(TrainingProjectIntroductionVo introductionVo, GetEnrollVO enroll, Long currentTime) {

        if (enroll.getNeedAudit()) {
            Integer auditStatus = enroll.getAuditStatus();//审核状态：1：待审核，2：审核通过，3：审核不通过，0：不需要审核
            switch (auditStatus) {
                case 1:
                    introductionVo.setAuditStutasCodeName(Constants.TRAINING_MSG_AUDIT_ING.getName());
                    introductionVo.setTitleStutasCodeName(Constants.TRAINING_MSG_AUDIT_ING_NOT_STUDY.getName());//报名审核中,无法进行项目学习！
                    introductionVo.setStatus(7);
                    break;
                case 2:
                    introductionVo = judgeTime(introductionVo, currentTime);
                    break;
                case 3:
                    introductionVo.setAuditStutasCodeName(Constants.TRAINING_MSG_AUDIT_FAIL.getName());
                    introductionVo.setTitleStutasCodeName(Constants.TRAINING_MSG_AUDIT_FAIL_NOT_STUDY.getName());//报名审核未通过,无法进行项目学习！
                    introductionVo.setStatus(8);
                    break;
                case 0:
                    introductionVo = judgeTime(introductionVo, currentTime);
                    break;
            }
        } else {

            //根据当前时间判断培训项目能否学习
            introductionVo = judgeTime(introductionVo, currentTime);
        }
        return introductionVo;
    }


    /**
     * 需要报名，根据当前时间，判断能否报名
     *
     * @param introductionVo 培训信息表
     * @param enroll         报名信息表
     * @param currentTime    当前时间
     * @param hasLimitNums   据此判断报名项目的人数报名类型 false--无限制 、true--有限制
     * @return
     */
    private TrainingProjectIntroductionVo jugdeEnrollStatus(TrainingProjectIntroductionVo introductionVo, GetEnrollVO enroll, Long currentTime, Boolean hasLimitNums) {
        //报名开始时间
        Long enrollStartTime = enroll.getStartTime().getTime();
        //报名结束时间
        Long enrollEndTime = enroll.getEndTime().getTime();

        if (enrollStartTime <= currentTime && enrollEndTime >= currentTime) {
            //判断是否名额已满
            introductionVo = whetherMembersFull(introductionVo, enroll, hasLimitNums);

        } else if (currentTime < enrollStartTime) {
            //报名尚未开始，无法进行项目学习！
            introductionVo.setTitleStutasCodeName(Constants.TRAINING_MSG_ENROLL_NOT_START.getName());
            introductionVo.setMemberStutasCodeName(Constants.TRAINING_MSG_ENROLL_NO_START.getName());
            introductionVo.setStatus(3);
        } else if (currentTime > enrollEndTime) {
            //报名已结束，无法进行项目学习！
            introductionVo.setTitleStutasCodeName(Constants.TRAINING_MSG_ENROLL_IS_END.getName());
            introductionVo.setMemberStutasCodeName(Constants.TRAINING_MSG_ENROLL_END.getName());
            introductionVo.setStatus(4);
        }
        return introductionVo;
    }

    /**
     * //判断是否名额已满
     *
     * @param introductionVo
     * @param enroll
     * @param hasLimitNums   据此判断报名项目的人数报名类型 false--无限制 、true--有限制
     * @return
     */
    private TrainingProjectIntroductionVo whetherMembersFull(TrainingProjectIntroductionVo introductionVo, GetEnrollVO enroll, Boolean hasLimitNums) {


        Integer enrollLimit = 0;
        Integer HasEnrolledNum = introductionVo.getHasEnrolledNum(); //已参与人数
        if (hasLimitNums) {
            enrollLimit = enroll.getLimit();    //限制名额
        } else {
            enrollLimit = introductionVo.getTrMembers();    //项目为无人数限制类型，取指定范围人数,已在后台实现；
        }
        if (null != enrollLimit && null != HasEnrolledNum) {
            if (enrollLimit > HasEnrolledNum) {
                introductionVo.setMemberStutas(1);
                introductionVo.setMemberStutasCodeName(Constants.TRAINING_MSG_IMMEDIATELY_ENROLL.getName());//立即报名
                //您尚未报名，报名成功后可进行学习。
                introductionVo.setTitleStutasCodeName(Constants.TRAINING_MSG_ONLY_AUDIT_SUCCESS_TO_SEE_ACTIVITY.getName());
                introductionVo.setStatus(5);
            } else {
                introductionVo.setMemberStutas(2);//名额已满
                introductionVo.setMemberStutasCodeName(Constants.TRAINING_MSG_QUOTA_FULL.getName());
                //名额已满,无法进行项目学习！
                introductionVo.setTitleStutasCodeName(Constants.TRAINING_MSG_QUOTA_FULL_NOT_STUDY.getName());
                introductionVo.setStatus(6);
            }
        }
        return introductionVo;
    }


    /**
     * 根据当前时间判断培训项目能否学习
     *
     * @param introductionVo
     * @param currentTime
     * @return
     */
    private TrainingProjectIntroductionVo judgeTime(TrainingProjectIntroductionVo introductionVo, Long currentTime) {
        if (introductionVo.getHasFinished()) {
            //项目已完成 返回已完成状态
            introductionVo.setAuditStutasCodeName(Constants.TRAINING_MSG_FINISHED.getName());
            introductionVo.setStatus(2);
        } else {
            if (introductionVo.getStartTime().getTime() <= currentTime) {
                introductionVo.setAuditStutasCodeName(Constants.TRAINING_MSG_START_LEARNING.getName());
                introductionVo.setStatus(2);

            } else {
                //培训时间未开始，请等待！
                introductionVo.setTitleStutasCodeName(Constants.TRAINING_MSG_TIME_NOT_STARTED.getName());
                introductionVo.setAuditStutasCodeName(Constants.TRAINING_MSG_START_LEARNING.getName());
                introductionVo.setStatus(1);
            }
        }
        return introductionVo;
    }



}
