package com.yizhi.application.sign.controller;

import com.baomidou.mybatisplus.plugins.Page;
import com.yizhi.core.application.cache.RedisCache;
import com.yizhi.core.application.context.ContextHolder;
import com.yizhi.core.application.context.RequestContext;
import com.yizhi.core.application.event.EventWrapper;
import com.yizhi.core.application.publish.CloudEventPublisher;
import com.yizhi.core.application.task.AbstractTaskHandler;
import com.yizhi.core.application.task.TaskExecutor;
import com.yizhi.sign.application.feign.SignApiClient;
import com.yizhi.sign.application.feign.SignRecordApiClient;
import com.yizhi.sign.application.vo.*;
import com.yizhi.sign.application.vo.domain.TrSignAccount;
import com.yizhi.site.application.feign.api.EventTrackApiClients;
import com.yizhi.system.application.vo.domain.Account;
import com.yizhi.training.application.feign.TrainingProjectClient;
import com.yizhi.training.application.vo.domain.TpAuthorizationRangeVo;
import com.yizhi.training.application.vo.domain.TrainingProjectVo;
import com.yizhi.util.application.constant.QueueConstant;
import com.yizhi.util.application.constant.ReturnCode;
import com.yizhi.util.application.constant.TpActivityType;
import com.yizhi.util.application.domain.Response;
import com.yizhi.util.application.event.TrainingProjectEvent;
import com.yizhi.util.application.json.JsonUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 签到主体表，入口在培训项目 前端控制器 学员端
 * </p>
 *
 * @author fanchunhui123
 * @since 2018-03-07
 */
@Api(tags = "签到-学员端", description = "签到-学员端")
@RestController
@RequestMapping("/api/sign")
public class SignApiController {

    @Autowired
    private SignApiClient signClient;
    @Autowired
    SignRecordApiClient signRecordApiClient;
    @Autowired
    private TrainingProjectClient trainingProjectClient;
    @Autowired
    private TaskExecutor taskExecutor;
    @Autowired
    private CloudEventPublisher cloudEventPublisher;

    @Autowired
    private EventTrackApiClients eventTrackApiClients;
    @Autowired
    private RedisCache redisCache;


    private static final Logger LOG = LoggerFactory.getLogger(SignApiController.class);

    //2018.09.13添加扫码查看接口
    @ApiOperation(value = "签到（扫码进入）", notes = "签到（扫码进入）")
    @PostMapping(value = "/scan")
    public Response<Object> signScan(HttpServletRequest request,@RequestBody SignVO signVO) {
        RequestContext requestContext = ContextHolder.get();
        Long projectId = signVO.getTrainingProjectId();
        List<Long> relationIds = requestContext.getRelationIds();
        Long siteId = requestContext.getSiteId();
        Long accountId = requestContext.getAccountId();
        Map<String, String> signMap = new HashMap<String, String>(1);
        boolean isPass = false;
        TrainingProjectVo project = trainingProjectClient.getOne(projectId);
        Integer range = project.getVisibleRange();
        if (range != null && range == 1) {
            if (siteId != null && project.getSiteId() != null && siteId.equals(project.getSiteId())) {
                isPass = true;
            }
        } else if (range != null && range == 0 && siteId.equals(project.getSiteId())) {
            List<TpAuthorizationRangeVo> tpAuthorizationRanges = trainingProjectClient.VisibleRange(projectId);
            List<Long> rangeIds = new ArrayList<>();
            if (tpAuthorizationRanges != null && tpAuthorizationRanges.size() > 0) {
                rangeIds = tpAuthorizationRanges.stream().map(TpAuthorizationRangeVo::getRelationId).collect(Collectors.toList());
                LOG.info("rangeIds" + rangeIds.toString());
            }
            if (rangeIds.contains(accountId)) {
                isPass = true;
            } else {
                for (Long relationId : relationIds) {
                    if (rangeIds.contains(relationId)) {
                        isPass = true;
                        break;
                    }
                }
            }
        }
        if (isPass) {
            return sign(request,signVO);
        } else {
            signMap.put("code", "6");
            signMap.put("name", "您没有权限访问该项目");
            return Response.ok(signMap);
        }
    }

    @ApiOperation(value = "签到（扫码进入）", notes = "签到（扫码进入）")
    @PostMapping(value = "/custom/scan")
    public Response<Object> customSignScan(HttpServletRequest request,@RequestBody SignVO signVO) {
        RequestContext requestContext = ContextHolder.get();
        signVO.setSignType(1);
        Long projectId = signVO.getTrainingProjectId();
        List<Long> relationIds = requestContext.getRelationIds();
        Long siteId = requestContext.getSiteId();
        Long accountId = requestContext.getAccountId();
        Map<String, String> signMap = new HashMap<String, String>();
        boolean isPass = false;
        TrainingProjectVo project = trainingProjectClient.getOne(projectId);
        Integer range = project.getVisibleRange();
        if (range != null && range == 1) {
            if (siteId != null && project.getSiteId() != null && siteId.equals(project.getSiteId())) {
                isPass = true;
            }
        } else if (range != null && range == 0 && siteId.equals(project.getSiteId())) {
            List<TpAuthorizationRangeVo> tpAuthorizationRanges = trainingProjectClient.VisibleRange(projectId);
            List<Long> rangeIds = new ArrayList<>();
            if (tpAuthorizationRanges != null && tpAuthorizationRanges.size() > 0) {
                rangeIds = tpAuthorizationRanges.stream().map(TpAuthorizationRangeVo::getRelationId).collect(Collectors.toList());
                LOG.info("rangeIds" + rangeIds.toString());
            }
            if (rangeIds.contains(accountId)) {
                isPass = true;
            } else {
                for (Long relationId : relationIds) {
                    if (rangeIds.contains(relationId)) {
                        isPass = true;
                        break;
                    }
                }
            }
        }
        if (isPass) {
            return sign(request,signVO);
        } else {
            return Response.fail("4001", "签到失败,您不在该项目范围内");
        }
    }

    @ApiOperation(value = "签到", notes = "签到")
    @PostMapping(value = "/")
    public Response<Object> sign(HttpServletRequest request, @RequestBody SignVO signVO) {
        RequestContext requestContext = ContextHolder.get();
        Long accountId = requestContext.getAccountId();
        Map<String, String> signMap = new HashMap<String, String>();
        boolean isPass = false;
        if (null == requestContext) {
            signMap.put("code", "0");
            signMap.put("name", "非法签到");
            return Response.ok(signMap);
        }
        signVO.setAccountId(accountId);
        // 查询是否签到
        String result = signClient.sign(signVO);
        if (result.equals("签到时间未开始")) {
            signMap.put("code", "1");
            signMap.put("name", result);
        } else if (result.equals("签到成功")) {
            // 添加活动签到埋点
           // if(request.getHeader("Cookie")!=null&&Objects.equals(redisCache.get(request.getHeader("Cookie").replace("JSESSIONID=","")),"2")){
                eventTrackApiClients.addEvent("event_activity_sign",accountId);
          //  }
            signMap.put("code", "2");
            signMap.put("name", result);
        } else if (result.equals("您已签到成功")) {
            signMap.put("code", "3");
            signMap.put("name", result);
        } else if (result.equals("补签成功")) {
            signMap.put("code", "4");
            signMap.put("name", result);
        } else if (result.equals("签到失败,签到时间已过")) {
            signMap.put("code", "5");
            signMap.put("name", result);
        } else {
            signMap.put("code", "0");
            signMap.put("name", result);
        }
        LOG.info(result);

        // 向培训项目发送消息，告知业务已经完成
        try {
            EventWrapper<TrainingProjectEvent> eventWrapper = new EventWrapper<TrainingProjectEvent>(signVO.getId(), TrainingProjectEvent.getInstance(signVO.getId(), TpActivityType.TYPE_SIGN, accountId, new Date(), requestContext.getSiteId()));
            LOG.info("向培训项目发送消息，告知签到业务已经完成:{}", eventWrapper);
            taskExecutor.asynExecute(new AbstractTaskHandler() {
                @Override
                public void handle() {
                    try {
                        cloudEventPublisher.publish(QueueConstant.TRAINING_PROJECT_EVENT_QUEUE, eventWrapper);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            LOG.info("签到业务向培训项目发送消息告知已经完成，失败：{}", e);
        }

        return Response.ok(signMap);
    }


    @ApiOperation(value = "我的签到", notes = "我的签到", httpMethod = "POST", response = TrSignRecordVo.class)
    @PostMapping("/my/record/list")
    public Response<Object> recordList(@RequestBody PageVO pageVO) {

        try {
            // 查询签到端
            RequestContext requestContext = ContextHolder.get();
            if (null == requestContext) {
                return Response.ok("非法获取我的签到");
            }
            Long accountId = requestContext.getAccountId();
            pageVO.setAccountId(accountId);
            Page<TrSignRecordVo> page = signClient.recordList(pageVO);
            Map<String, Integer> pageMap = new HashMap<String, Integer>();
            pageMap.put("pageNo", pageVO.getPageNo());
            pageMap.put("pageSize", pageVO.getPageSize());
            pageMap.put("pageTotal", page.getTotal());

            List<TrSignRecordVo> listPage = page.getRecords();
            TrainingProjectVo pro = null;
            if (null != listPage) {
                for (TrSignRecordVo item : listPage) {
                    pro = trainingProjectClient.getOne(item.getTrainingProjectId());
                    if (null != pro) {
                        item.setTrainingProjectName(pro.getName());
                    }
                }
            }
			/*Map<String,Object> map = signClient.recordList(pageVO);
			if(map == null){
				Response.fail(ReturnCode.RESOURCE_NOT_FOUND);
			}

			List<TrSignRecordVo> listPage = (List<TrSignRecordVo>) map.get("list");
			TrainingProject pro = null;
			if(null != listPage){
				for(TrSignRecordVo item : listPage){
					pro = trainingProjectClient.getOne(item.getTrainingProjectId());
					if(null != pro){
						item.setTrainingProjectName(pro.getName());
					}
				}
			}
			Map<String,Integer> pageMap = (Map<String, Integer>) map.get("page"); */
            return Response.ok(listPage, pageMap);
        } catch (Exception e) {
            LOG.error("", e);
            return Response.fail(ReturnCode.SERVICE_UNAVAILABLE.getCode(),ReturnCode.SERVICE_UNAVAILABLE.getMsg());
        }
    }

    /**
     * 我的签到总数量
     */
    @ApiOperation(value = "我的签到总数量", notes = "我的签到总数量")
    @GetMapping("/record/count")
    public Response<Integer> selectSignRecordCountByAccountId() {
        try {
            RequestContext requestContext = ContextHolder.get();
            if (null == requestContext) {
                return Response.ok(0);
            }
            Long accountId = requestContext.getAccountId();
            return Response.ok(signRecordApiClient.selectSignRecordCountByAccountId(accountId));
        } catch (Exception e) {
            LOG.error("", e);
            return Response.fail(ReturnCode.SERVICE_UNAVAILABLE.getCode(),ReturnCode.SERVICE_UNAVAILABLE.getMsg());
        }
    }
    
	@ApiOperation(value = "小程序验证签到邀请码", notes = "小程序验证签到邀请码", response = TrSignAccount.class)
	@GetMapping("/public/checkCode")
	public Response<String> checkCodeMini(
			@ApiParam(name = "code", value = "项目签到邀请码", required = false) @RequestParam(name = "code", required = true) String code,
			@ApiParam(name = "openId", value = "微信小程序openId 默认不传", required = false) @RequestParam(name = "openId", required = false) String openId,
			@ApiParam(name = "accountId", value = "用户id 默认不传", required = false) @RequestParam(name = "accountId", required = false) Long accountId){
		Map<String, Object> map = signClient.checkCode(code, openId, accountId);
		String error = (String) map.get("error");
		TrSignAccount success = JsonUtil.json2Ojbect((String)map.get("success"), TrSignAccount.class);
		if (StringUtils.isNotBlank(error)) {
			return Response.fail(error);
		}
		if (success!=null) {
			return Response.ok(success);
		}else {
			return Response.ok();
		}
	}
	
	@ApiOperation(value = "验证用户身份", notes = "验证用户身份", response = Account.class)
	@PostMapping("/public/checkAccount")
	public Response<String> checkAccount(@RequestBody SignAccountParam param){
		Map<String, Object> map = signClient.checkAccount(param);
		String error = (String) map.get("error");
		Account success = JsonUtil.json2Ojbect((String)map.get("success"), Account.class);
		if (StringUtils.isNotBlank(error)) {
			return Response.fail(error);
		}else {
			return Response.ok(success);
		}
	}
	
	@ApiOperation(value = "小程序签到详情", notes = "小程序签到详情", response = ApiSignTimeVO.class)
	@GetMapping("/public/signDetail")
	public Response<String> signDetailMini(
			@ApiParam(name = "accountId", value = "用户id ", required = false) @RequestParam(name = "accountId", required = false) Long accountId,
			@ApiParam(name = "code", value = "项目签到邀请码", required = true) @RequestParam(name = "code", required = true) String code) {
		return Response.ok(signClient.signDetail(accountId, code,null));
	}
	
	@ApiOperation(value = "签到详情", notes = "验证邀请码返回签到详情", response = ApiSignTimeVO.class)
	@GetMapping("/checkCode")
	public Response<String> signDetail(
			@ApiParam(name = "accountId", value = "用户id ", required = false) @RequestParam(name = "accountId", required = false) Long accountId,
			@ApiParam(name = "code", value = "项目签到邀请码", required = true) @RequestParam(name = "code", required = true) String code,
			@ApiParam(name = "trainingProjectId", value = "培训项目id ", required = true) @RequestParam(name = "trainingProjectId", required = true) Long trainingProjectId) {
		try {
			accountId = ContextHolder.get().getAccountId();
			ApiSignTimeVO vo = signClient.signDetail(accountId, code,trainingProjectId);
			if (!ObjectUtils.isEmpty(vo)) {
				Date endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(vo.getEndTime());
				long day = (System.currentTimeMillis() - endTime.getTime()) / (60 * 60 * 24 * 1000);
				if ((System.currentTimeMillis() - endTime.getTime())>0 && day >= 0 && day <= 7) {
					return Response.fail("签到已过期");
				}
				if (day > 7) {
					return Response.fail("无效邀请码,请重新输入");
				}
				return Response.ok(vo);
			}else {
				return Response.fail("无效邀请码,请重新输入");
			}
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			return Response.fail();
		}
		
	}
	
	@ApiOperation(value = "小程序签到切换用户", notes = "小程序签到切换用户")
	@GetMapping("/public/delRelation")
	public Response<String> delRelation(
			@ApiParam(name = "accountId", value = "用户id ", required = true) @RequestParam(name = "accountId", required = true) Long accountId,
			@ApiParam(name = "code", value = "项目签到邀请码", required = true) @RequestParam(name = "code", required = true) String code,
			@ApiParam(name = "openId", value = "微信小程序openId", required = true) @RequestParam(name = "openId", required = true) String openId) {
		String result = signClient.delRelation(accountId, code, openId);
		return result.equals("success")?Response.ok():Response.fail();
	}
	
    @ApiOperation(value = "签到（小程序）", notes = "签到（小程序）")
	@GetMapping("/public/insert")
	public Response<Object> insertMini(HttpServletRequest request,
			@ApiParam(name = "accountId", value = "用户id ", required = false) @RequestParam(name = "accountId", required = false) Long accountId,
			@ApiParam(name = "trainingProjectId", value = "项目id ", required = true) @RequestParam(name = "trainingProjectId", required = true) Long trainingProjectId,
			@ApiParam(name = "signTimeId", value = "签到id ", required = true) @RequestParam(name = "signTimeId", required = true) Long signTimeId,
			@ApiParam(name = "siteId", value = "签到id ", required = false) @RequestParam(name = "signTimeId", required = false) Long siteId) {
        Map<String, String> signMap = new HashMap<String, String>();
		SignVO signVO = new SignVO();
		signVO.setAccountId(accountId);
		signVO.setTrainingProjectId(trainingProjectId);
		signVO.setSignTimeId(signTimeId);
        // 查询是否签到
        String result = signClient.sign(signVO);
        if (result.equals("签到时间未开始")) {
            signMap.put("code", "1");
            signMap.put("name", result);
        } else if (result.equals("签到成功")) {
            // 添加活动签到埋点
            if(request.getHeader("Cookie")!=null&&Objects.equals(redisCache.get(request.getHeader("Cookie").replace("JSESSIONID=","")),"2")){
                eventTrackApiClients.addEvent("activit",accountId);
            }
            signMap.put("code", "2");
            signMap.put("name", result);
            signMap.put("signDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        } else if (result.equals("您已签到成功")) {
            signMap.put("code", "3");
            signMap.put("name", result);
        } else if (result.equals("补签成功")) {
            signMap.put("code", "4");
            signMap.put("name", result);
        } else if (result.equals("签到失败,签到时间已过")) {
            signMap.put("code", "5");
            signMap.put("name", result);
        } else {
            signMap.put("code", "0");
            signMap.put("name", result);
        }
        LOG.info(result);

        // 向培训项目发送消息，告知业务已经完成
        try {
            EventWrapper<TrainingProjectEvent> eventWrapper = new EventWrapper<TrainingProjectEvent>(signVO.getSignTimeId(), TrainingProjectEvent.getInstance(signVO.getSignTimeId(), TpActivityType.TYPE_SIGN, accountId, new Date(), siteId));
            LOG.info("向培训项目发送消息，告知签到业务已经完成:{}", eventWrapper);
            taskExecutor.asynExecute(new AbstractTaskHandler() {
                @Override
                public void handle() {
                    try {
                        cloudEventPublisher.publish(QueueConstant.TRAINING_PROJECT_EVENT_QUEUE, eventWrapper);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            LOG.info("签到业务向培训项目发送消息告知已经完成，失败：{}", e);
        }

        return Response.ok(signMap);
	}
    
    
    @ApiOperation(value = "签到", notes = "签到")
	@GetMapping("/insert")
	public Response<Object> insert(HttpServletRequest request,
			@ApiParam(name = "accountId", value = "用户id ", required = false) @RequestParam(name = "accountId", required = false) Long accountId,
			@ApiParam(name = "trainingProjectId", value = "项目id ", required = true) @RequestParam(name = "trainingProjectId", required = true) Long trainingProjectId,
			@ApiParam(name = "signTimeId", value = "签到id ", required = true) @RequestParam(name = "signTimeId", required = true) Long signTimeId,
			@ApiParam(name = "siteId", value = "签到id ", required = false) @RequestParam(name = "signTimeId", required = false) Long siteId) {
    	accountId = ContextHolder.get().getAccountId();
    	siteId = ContextHolder.get().getSiteId();
        Map<String, String> signMap = new HashMap<String, String>();
		SignVO signVO = new SignVO();
		signVO.setAccountId(accountId);
		signVO.setTrainingProjectId(trainingProjectId);
		signVO.setSignTimeId(signTimeId);
        // 查询是否签到
        String result = signClient.sign(signVO);
        if (result.equals("签到时间未开始")) {
            signMap.put("code", "1");
            signMap.put("name", result);
        } else if (result.equals("签到成功")) {
            // 添加活动签到埋点
            if(request.getHeader("Cookie")!=null&&Objects.equals(redisCache.get(request.getHeader("Cookie").replace("JSESSIONID=","")),"2")){
                eventTrackApiClients.addEvent("activit",accountId);
            }
            signMap.put("code", "2");
            signMap.put("name", result);
            signMap.put("signDate", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        } else if (result.equals("您已签到成功")) {
            signMap.put("code", "3");
            signMap.put("name", result);
        } else if (result.equals("补签成功")) {
            signMap.put("code", "4");
            signMap.put("name", result);
        } else if (result.equals("签到失败,签到时间已过")) {
            signMap.put("code", "5");
            signMap.put("name", result);
        } else {
            signMap.put("code", "0");
            signMap.put("name", result);
        }
        LOG.info(result);

        // 向培训项目发送消息，告知业务已经完成
        try {
            EventWrapper<TrainingProjectEvent> eventWrapper = new EventWrapper<TrainingProjectEvent>(signVO.getSignTimeId(), TrainingProjectEvent.getInstance(signVO.getSignTimeId(), TpActivityType.TYPE_SIGN, accountId, new Date(), siteId));
            LOG.info("向培训项目发送消息，告知签到业务已经完成:{}", eventWrapper);
            taskExecutor.asynExecute(new AbstractTaskHandler() {
                @Override
                public void handle() {
                    try {
                        cloudEventPublisher.publish(QueueConstant.TRAINING_PROJECT_EVENT_QUEUE, eventWrapper);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            LOG.info("签到业务向培训项目发送消息告知已经完成，失败：{}", e);
        }

        return Response.ok(signMap);
	}
}

