package com.qiankun.controller.mdp;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.WxMaUserService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qiankun.annotation.Auth;
import com.qiankun.config.WxMaConfiguration;
import com.qiankun.config.WxMaProperties;
import com.qiankun.controller.base.BaseController;
import com.qiankun.dao.UserDao;
import com.qiankun.dao.core.Hints;
import com.qiankun.entity.*;
import com.qiankun.pages.IPageList;
import com.qiankun.service.ActivityService;
import com.qiankun.service.BloodService;
import com.qiankun.service.UserService;
import com.qiankun.utils.JwtTokenUtil;
import com.qiankun.utils.QRCodeUtil;
import com.qiankun.utils.UserUtils;
import com.qiankun.vo.*;
import com.sun.mail.imap.ResyncData;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.omg.PortableInterceptor.ServerRequestInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;

@RestController
@RequestMapping("/wx/mdp")
public class MdpController extends BaseController<Object> {
    private final Logger logger = LoggerFactory.getLogger(MdpController.class);
    @Autowired
    private JwtTokenUtil tokenUtil;
    @Autowired
    private WxMaProperties propertis;
    @Autowired
    private UserService userService;
    @Autowired
    private ActivityService activityService;
    @Autowired
    private BloodService bloodService;
    private ResourceBundle rb = ResourceBundle.getBundle("system");
    private String getAppid(){
        return propertis.getConfigs().get(1).getAppid();
    }
    private String uploadAvatarPath = File.separator + "mdp" + File.separator + "uploadAvatar";
    private String certificateTemplate = "classpath:certificate.png";
    private String userCertificatePath = File.separator + "mdp" + File.separator + "certificate";

    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/login",method = RequestMethod.GET)
    public Map<String,Object> login(@RequestParam String code) throws Exception {
        if (StringUtils.isBlank(code)) {
            return null;
        }

        final WxMaService wxService = WxMaConfiguration.getMaService(getAppid());

        try {
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
            this.logger.info(session.getSessionKey());
            this.logger.info(session.getOpenid());
            Map<String,Object> result = Maps.newConcurrentMap();

            User userInfo = userService.findByOpenid(session.getOpenid());
            if (userInfo != null){
                String sKey = tokenUtil.generateToken(userInfo.getOpenid());
                result.put("sKey",sKey);
                result.put("userInfo", UserUtils.converToVo(userInfo));
            }else {
                result.put("sKey","");
                result.put("userInfo","");
                result.put("openid",session.getOpenid());
            }

            return result;
        } catch (WxErrorException e) {
            this.logger.error(e.getMessage(), e);
            throw new Exception(e.getMessage(),e);
        }
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value ="/loginByPaperId",method = RequestMethod.POST)
    public Map<String,Object> loginByPaperId(@RequestBody PaperIdLoginVo vo){
        User user = userService.findByPaperId(vo.getPaperId(),vo.getPaperType());
        Map<String,Object> result = Maps.newConcurrentMap();
        if (user == null){
            //新用户
            result.put("isExist",false);
        }else {
            //老用户
            if (!user.getName().equals(vo.getName())){
                result.put("errorMsg","姓名与库中信息不符，请核实后重新提交");
            }else if(!Strings.isNullOrEmpty(user.getOpenid())){
                result.put("errorMsg","该用户已与其他微信绑定");
            }else {

                user.setOpenid(vo.getOpenid());
                if (!Strings.isNullOrEmpty(vo.getPhone())){
                    //更新微信绑定的手机号
                    user.setMobile(vo.getPhone());
                }
                userService.save(user);
                result.put("sKey",tokenUtil.generateToken(user.getOpenid()));
                result.put("userInfo",UserUtils.converToVo(user));
            }
            result.put("isExist",true);
        }
        return result;
    }

    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/userInfo",method = RequestMethod.GET)
    public UserVo getUserInfo(@RequestHeader String sKey){
        if (Strings.isNullOrEmpty(sKey)){
            throw new IllegalArgumentException("请求参数错误");
        }
        String openid = tokenUtil.getUsernameFromToken(sKey);
        User user = userService.findByOpenid(openid);
        return UserUtils.converToVo(user);
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/findUser",method = RequestMethod.GET)
    public UserVo findUserById(@RequestParam String id){
        User user = userService.findById(id);
        return UserUtils.converToVo(user);
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/decryptedData",method = RequestMethod.POST)
    public Map<String,Object> decryptedData(@RequestBody DecryptedDataVo dataVo){
        Map<String,Object> result = Maps.newConcurrentMap();
        final WxMaService wxService = WxMaConfiguration.getMaService(getAppid());
        try {
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(dataVo.getCode());
            WxMaUserService wxUserService = wxService.getUserService();
            WxMaPhoneNumberInfo phoneInfo = wxUserService.getPhoneNoInfo(session.getSessionKey(),dataVo.getEncryptedData(),dataVo.getIv());
            result.put("status","ok");
            result.put("phoneInfo",phoneInfo);
        } catch (WxErrorException e) {
            result.put("status","error");
            result.put("errorMsg","微信登陆失败");
        }
        return result;
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/uploadAvatar",method = RequestMethod.POST)
    public Map<String,String> uploadAvatar(MultipartFile file,@RequestHeader String sKey){
        Map<String,String> result = Maps.newConcurrentMap();
        if (Strings.isNullOrEmpty(sKey)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String openid = tokenUtil.getUsernameFromToken(sKey);
        User user = userService.findByOpenid(openid);
        if (user == null){
            result.put("status","error");
            result.put("errorMsg","用户不存在");
            return result;
        }
        try{
            if (file != null && !file.isEmpty()){
                String originalFileName = file.getOriginalFilename();
                String rootPath = rb.getString("file_path");
                File destFile = new File(rootPath + uploadAvatarPath,originalFileName);
                FileUtils.writeByteArrayToFile(destFile,file.getBytes());
                user.setAvatarImage(uploadAvatarPath + File.separator + originalFileName);
                userService.save(user);
                result.put("status","ok");
                result.put("avatarImage",user.getAvatarImage());
            }else {
                result.put("status","error");
                result.put("errorMsg","上传文件不存在");
                return result;
            }
        }catch (IOException e){
            logger.error(e.getMessage(),e);
            result.put("status","error");
            result.put("errorMsg","上传文件失败");
        }

        return result;
    }

    /**
     * 获取用户积分、参与的活动等相关信息
     * @param sKey
     * @return
     */
    @Auth(verifyURL = false,verifyLogin = false)
    @RequestMapping(value = "/userActivityInfo",method = RequestMethod.GET)
    public Map<String,Object> getUserActivityInfo(@RequestHeader String sKey){
        Map<String,Object> result = Maps.newConcurrentMap();
        if (Strings.isNullOrEmpty(sKey)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String openid = tokenUtil.getUsernameFromToken(sKey);
        User user = userService.findByOpenid(openid);
        if (user == null){
            result.put("status","error");
            result.put("errorMsg","用户不存在");
            return result;
        }

        if (!userInfoisComplete(user)){
            result.put("userInfoStatus","unComplete");
        }else{
            result.put("userInfoStatus","complete");
        }
        result.put("points",getUserPoints(user));
        result.put("status","ok");
        return result;
    }
    private boolean userInfoisComplete(User user){
        if (Strings.isNullOrEmpty(user.getName()) ||
                Strings.isNullOrEmpty(user.getBirthday()) ||
                Strings.isNullOrEmpty(user.getPaperType()) ||
                Strings.isNullOrEmpty(user.getPaperId()) ||
                Strings.isNullOrEmpty(user.getNation()) ||
                Strings.isNullOrEmpty(user.getNationality()) ||
                Strings.isNullOrEmpty(user.getNativePlace()) ||
                Strings.isNullOrEmpty(user.getAddr()) ||
                Strings.isNullOrEmpty(user.getMobile()) ||
                Strings.isNullOrEmpty(user.getQq()) ||
                !validateContacts(user)) {
            return false;
        }
        return true;
    }
    /**
     * 获取用户积分
     * @param user
     * @return
     */
    private int getUserPoints(User user){
        return 0;
    }
    private boolean validateContacts(User user){
        boolean flag = true;
        Set<Contacts> sets = user.getContacts();
        if (sets == null){
            flag = false;
        }else {
            Iterator<Contacts> it = sets.iterator();
            while (it.hasNext()){
                Contacts c = it.next();
                if (Strings.isNullOrEmpty(c.getName()) ||
                    Strings.isNullOrEmpty(c.getRelation()) ||
                    Strings.isNullOrEmpty(c.getMobile())){
                    flag = false;
                    break;
                }
            }
        }
        return flag;
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/loadResource",method = RequestMethod.GET)
    public ResponseEntity<byte[]> loadResource(@RequestParam String imageName) throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        File file = new File(rb.getString("file_path"),imageName);
        return new ResponseEntity<>(FileUtils.readFileToByteArray(file),headers, HttpStatus.OK);
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/userQrcode",method = RequestMethod.GET)
    public void getUserQrcode(@RequestParam String id, HttpServletResponse response) throws Exception {
        QRCodeUtil.generateQRCode(id,100,100,"png",response);
        response.flushBuffer();
    }

    @Auth(verifyURL = false,verifyLogin = false)
    @RequestMapping(value = "/activity/list",method = RequestMethod.GET)
    public Map<String,Object> getActivityList(@RequestParam(required = false) String userId, HttpServletResponse response, HttpServletRequest request){
        IPageList<Activity> userPage = activityService.findPageList(userId,new Hints(getStartRow(request),getPageCount(request)));

        Map<String, Object> map = new HashMap<>();
        map.put("activityData", userPage);
        map.put("pageCount", getPageCount(request));
        map.put("pageNumber", getPageNumber(request));
        return map;
    }

    /**
     * 活动报名
     * @param userId
     * @param activityId
     * @return
     */
    @Auth(verifyURL = false,verifyLogin = false)
    @RequestMapping(value = "/activity/apply",method = RequestMethod.GET)
    public Map<String,Object> activityApply(@RequestParam String userId,@RequestParam String activityId){
        Map<String,Object> result = Maps.newConcurrentMap();
        User user = userService.findById(userId);
        if (user == null){
            result.put("status","error");
            result.put("errorMsg","用户不存在");
            return result;
        }
        Activity activity = activityService.findById(activityId);
        if (activity == null){
            result.put("status","error");
            result.put("errorMsg","活动不存在");
            return result;
        }else if (!activity.isAvailable()){
            result.put("status","error");
            result.put("errorMsg","活动已关闭");
            return result;
        }else if (activity.getActivityReg().size() >= activity.getMax()){
            result.put("status","error");
            result.put("errorMsg","活动报名人数已达上限");
            return result;
        }
        if (activity.getType().equals("1")){
            //采血活动，需验证个人信息是否已完善
            if (!userInfoisComplete(user)){
                result.put("status","error");
                result.put("errorMsg","请先完善个人信息后再报名");
                return result;
            }
        }
        ActivityReg reg = new ActivityReg();
        reg.setUser(user);
        reg.setActivity(activity);
        activityService.saveActivityReg(reg);
        result.put("status","ok");
        return result;
    }

    /**
     * 采血
     * @param formData
     * @param sKey
     * @return
     */
    @Auth(verifyURL = false,verifyLogin = false)
    @RequestMapping(value = "/activity/collectionBlood",method = RequestMethod.POST)
    public Map<String,Object> collectionBlood(@RequestBody Map<String,String> formData,@RequestHeader String sKey){
        Map<String,Object> result = Maps.newConcurrentMap();
        if (Strings.isNullOrEmpty(sKey)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String openid = tokenUtil.getUsernameFromToken(sKey);
        if (Strings.isNullOrEmpty(openid)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String userId = formData.get("userId");
        String activityId = formData.get("activityId");
        String bloodId = formData.get("bloodId");

        User user = userService.findById(userId);
        Activity activity = activityService.findById(activityId);
        //验证一个用户在一次采血活动中只能有一次采血
        boolean isExist = bloodService.isExistByUserAndActivty(user,activity);
        if (isExist){
            result.put("status","error");
            result.put("errorMsg","该用户已经采血，请不要重复采集");
            return result;
        }
        Blood blood = new Blood();
        blood.setBloodId(bloodId);
        blood.setBloodAddr(activity.getAddr());
        blood.setUpdateTime(new Date());
        blood.setUser(user);
        blood.setActivity(activity);
        bloodService.save(blood);
        //修改用户状态
        user.setStatus("2");
        userService.save(user);
        result.put("status","ok");
        return result;
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/activity/signin",method = RequestMethod.POST)
    public Map<String,Object> activitySignin(@RequestBody Map<String,String> formData,@RequestHeader String sKey){
        Map<String,Object> result = Maps.newConcurrentMap();
        if (Strings.isNullOrEmpty(sKey)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String openid = tokenUtil.getUsernameFromToken(sKey);
        if (Strings.isNullOrEmpty(openid)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String userId = formData.get("userId");
        String activityId = formData.get("activityId");
        ActivityReg reg = activityService.signin(userId,activityId);
        result.put("status","ok");
        result.put("activityReg",reg);
        return result;
    }
    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/activity/signout",method = RequestMethod.POST)
    public Map<String,Object> activitySignout(@RequestBody Map<String,String> formData,@RequestHeader String sKey){
        Map<String,Object> result = Maps.newConcurrentMap();
        if (Strings.isNullOrEmpty(sKey)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String openid = tokenUtil.getUsernameFromToken(sKey);
        if (Strings.isNullOrEmpty(openid)){
            result.put("status","error");
            result.put("errorMsg","请求参数错误");
            return result;
        }
        String userId = formData.get("userId");
        String activityId = formData.get("activityId");
        ActivityReg reg = activityService.signout(userId,activityId);
        result.put("status","ok");
        result.put("activityReg",reg);
        return result;
    }

    @Auth(verifyLogin = false,verifyURL = false)
    @RequestMapping(value = "/user/generateCertificate",method = RequestMethod.GET)
    public Map<String,Object> generateCertificate(@RequestHeader String sKey){
        Map<String,Object> result = Maps.newHashMap();
        String openid = tokenUtil.getUsernameFromToken(sKey);
        User user = userService.findByOpenid(openid);
        if (user == null){
            result.put("status","error");
            result.put("errorMsg","用户不存在");
            return result;
        }
        if ("1".equals(user.getStatus()) || "3".equals(user.getStatus())){
            //未采血或退库的没有证书
            result.put("status","error");
            result.put("errorMsg","您还未采血，不能生成证书");
            return result;
        }
        String code = getCollectBloodCode(user);
        if (Strings.isNullOrEmpty(code)){
            result.put("status","error");
            result.put("errorMsg","采血编号不存在");
            return result;
        }
        if (Strings.isNullOrEmpty(user.getCerfificatePath())){
            try {
                generateCertificate(user,code);
            } catch (IOException e) {
                logger.error(e.getMessage(),e);
                result.put("status","error");
                result.put("errorMsg","生成证书错误");
                return result;
            }
            userService.save(user);
        }
        result.put("status","ok");
        result.put("certificateImage",user.getCerfificatePath());
        return result;
    }
    private void generateCertificate(User user,String code) throws IOException {
        List<CertificateVo> addTexts = Lists.newArrayList();
        Calendar now = Calendar.getInstance();

        String year = now.get(Calendar.YEAR) + "";
        String month = now.get(Calendar.MONTH) + 1 >=10 ? "" + (now.get(Calendar.MONTH) + 1) : "0" + (now.get(Calendar.MONTH) + 1);
        String day = now.get(Calendar.DATE) >=10 ? "" + now.get(Calendar.DATE) : "0" + now.get(Calendar.DATE);
        addTexts.add(new CertificateVo(user.getName(),new Font("宋体",Font.BOLD,50),190,570));
        addTexts.add(new CertificateVo(code,new Font("宋体",Font.BOLD,30),270,1265));
        addTexts.add(new CertificateVo(year,new Font("宋体",Font.PLAIN,30),525,1200));
        addTexts.add(new CertificateVo(month,new Font("宋体",Font.PLAIN,30),650,1200));
        addTexts.add(new CertificateVo(day,new Font("宋体",Font.PLAIN,30),740,1200));
        String outputFilePath = rb.getString("file_path") + this.userCertificatePath + File.separator + user.getId() + ".png";
        UserUtils.generateCertificate(this.certificateTemplate,outputFilePath,addTexts);
        user.setCerfificatePath(this.userCertificatePath + File.separator + user.getId() + ".png");
    }

    private String getCollectBloodCode(User user) {
        String code = "";
        List<Blood> collectionBloods = bloodService.findByUserId(user);
        if (!CollectionUtils.isEmpty(collectionBloods)){
            Blood b = collectionBloods.get(0);
            code = b.getBloodId();
        }
        return code;
    }
}
