package com.izouma.awesomeadmin.service.impl;

import com.izouma.awesomeadmin.constant.AppConstant;
import com.izouma.awesomeadmin.dao.*;
import com.izouma.awesomeadmin.dto.Page;
import com.izouma.awesomeadmin.model.AlipayTemp;
import com.izouma.awesomeadmin.model.UserInfo;
import com.izouma.awesomeadmin.service.OSSFileService;
import com.izouma.awesomeadmin.service.UserInfoService;
import com.izouma.awesomeadmin.util.MD5Util;
import com.izouma.awesomeadmin.util.PropertiesFileLoader;
import com.izouma.awesomeadmin.util.WeixinUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import io.rong.RongCloud;
import io.rong.models.SMSVerifyCodeResult;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * user_info service接口实现类
 * Tue Apr 17 10:32:49 CST 2018  Suo Chen Cheng
 */
@Service
public class UserInfoServiceImpl implements UserInfoService {

    private static Logger logger = Logger.getLogger(UserInfoServiceImpl.class);
    private RongCloud rongCloud = RongCloud.getInstance(PropertiesFileLoader.getProperties("rongyunappkey"), PropertiesFileLoader.getProperties("rongyunappsecret"));

    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private DepartInfoMapper departInfoMapper;
    @Autowired
    private SysAppTokenMapper sysAppTokenMapper;

    @Autowired
    private OSSFileService ossFileService;

    @Autowired
    private AlipayTempMapper alipayTempMapper;

    @Override
    public List<UserInfo> getUserInfoList(UserInfo record) {

        logger.info("getUserInfoList");
        try {

            return userInfoMapper.queryAllUserInfo(record);
        } catch (Exception e) {
            logger.error("getUserInfoList", e);
        }

        return null;
    }

    @Override
    public List<UserInfo> getUserInfoByPage(Page page, UserInfo record) {

        logger.info("getUserInfoByPage");
        try {

            Map<String, Object> parameter = new HashMap<String, Object>();
            parameter.put("record", record);
            parameter.put(AppConstant.PAGE, page);

            return userInfoMapper.queryUserInfosByPage(parameter);
        } catch (Exception e) {
            logger.error("getUserInfoByPage", e);
        }

        return null;
    }

    @Override
    public UserInfo getUserInfoById(String id) {

        logger.info("getUserInfoById");
        try {

            return userInfoMapper.selectByPrimaryKey(Integer.valueOf(id));
        } catch (Exception e) {
            logger.error("getUserInfoById", e);
        }

        return null;
    }

    @Override
    public UserInfo getUserInfo(UserInfo record) {

        logger.info("getUserInfo");
        try {

            return userInfoMapper.queryUserInfo(record);
        } catch (Exception e) {
            logger.error("getUserInfo", e);
        }

        return null;
    }

    @Override
    public UserInfo getSingleUserInfo(UserInfo record) {

        logger.info("getSingleUserInfo");
        try {

            return userInfoMapper.querySingleUserInfo(record);
        } catch (Exception e) {
            logger.error("getSingleUserInfo", e);
        }

        return null;
    }

    @Override
    public boolean createUserInfo(UserInfo record) {

        logger.info("createUserInfo");
        try {
            if (StringUtils.isNotEmpty(record.getPassword())) {
                record.setPassword(MD5Util.getMD5(record.getPassword()));
            }
            int updates = userInfoMapper.insertSelective(record);

            if (updateUserRolesAndDeparts(record, updates)) return true;
        } catch (Exception e) {
            logger.error("createUserInfo", e);
        }

        return false;
    }

    private boolean updateUserRolesAndDeparts(UserInfo record, int updates) {
        if (updates > 0) {
            if (record.getDepartId() != null) {
                departInfoMapper.clearUserDeparts(record.getId());
                departInfoMapper.setUserDeparts(record.getId(), Arrays.asList(record.getDepartId().split(",")));
            }
            if (record.getRoleId() != null) {
                sysRoleMapper.clearUserRoles(record.getId());
                sysRoleMapper.setUserRoles(record.getId(), Arrays.asList(record.getRoleId().split(",")));
            }
            return true;
        }
        return false;
    }

    @Override
    public boolean deleteUserInfo(String id) {

        logger.info("deleteUserInfo");
        try {

            int updates = userInfoMapper.delete(id);
            departInfoMapper.clearUserDeparts(Integer.valueOf(id));
            sysRoleMapper.clearUserRoles(Integer.valueOf(id));

            if (updates > 0) {
                return true;
            }
        } catch (Exception e) {
            logger.error("deleteUserInfo", e);
        }

        return false;
    }

    @Override
    public boolean updateUserInfo(UserInfo record) {

        logger.info("updateUserInfo");
        try {

            int updates = userInfoMapper.updateByPrimaryKeySelective(record);

            if (updateUserRolesAndDeparts(record, updates)) return true;
        } catch (Exception e) {
            logger.error("updateUserInfo", e);
        }

        return false;
    }

    @Override
    public boolean updatePassword(UserInfo record) {

        logger.info("updatePassword");
        try {
            if (StringUtils.isNotEmpty(record.getPassword())) {
                record.setPassword(MD5Util.getMD5(record.getPassword()));
            }

            int updates = userInfoMapper.updatePassword(record);

            if (updates > 0) {
                return true;
            }
        } catch (Exception e) {
            logger.error("updatePassword", e);
        }

        return false;
    }

    @Override
    public UserInfo login(String username, String password) {
        logger.info("login");
        try {
            Map<String, Object> map = new HashMap<>();
            map.put("username", username);
            map.put("password", MD5Util.getMD5(password));
            UserInfo result = userInfoMapper.login(map);
            return result;
        } catch (Exception e) {
            logger.error("login", e);
        }
        return null;
    }

//    @Override
//    public UserInfo loginSms(String phone, String code, String sessionId) throws LoginException {
//        logger.info("loginSms");
////        SMSVerifyCodeResult sMSVerifyCodeResult;
////        try {
////            sMSVerifyCodeResult = rongCloud.sms.verifyCode(sessionId, code);
////        } catch (Exception e) {
////            e.printStackTrace();
////            throw new LoginException("验证码错误");
////        }
//        try {
//            if (code.toLowerCase().equals(sessionId)) {
//                UserInfo userInfo = new UserInfo();
//                userInfo.setPhone(phone);
//                userInfo = getUserInfo(userInfo);
//                if (userInfo == null) {
//                    userInfo = new UserInfo();
//                    userInfo.setPhone(phone);
//                    userInfo.setUsername(phone);
//                    userInfo.setNickname(phone);
//                    userInfo.setIcon("https://microball.oss-cn-hangzhou.aliyuncs.com/huanbaojia/icon_morentouxiang.png");
//                    if (!createUserInfo(userInfo)) {
//                        throw new LoginException("登录失败");
//                    }
//                }
//                return userInfo;
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new LoginException("验证码错误");
//        }
//        throw new LoginException("验证码错误");
//    }


    @Override
    public UserInfo loginSms(String phone, String code, String sessionId) throws LoginException {
        logger.info("loginSms");
        SMSVerifyCodeResult sMSVerifyCodeResult;
        try {
            sMSVerifyCodeResult = rongCloud.sms.verifyCode(sessionId, code);
        } catch (Exception e) {
            e.printStackTrace();
            throw new LoginException("验证码错误");
        }
        if (200 == sMSVerifyCodeResult.getCode()) {
            Boolean success = sMSVerifyCodeResult.getSuccess();
            if (success) {
                UserInfo userInfo = new UserInfo();
                userInfo.setPhone(phone);
                userInfo = getUserInfo(userInfo);
                if (userInfo == null) {
                    userInfo = new UserInfo();
                    userInfo.setPhone(phone);
                    userInfo.setUsername(phone);
                    userInfo.setNickname(phone);
                    userInfo.setIcon("https://microball.oss-cn-hangzhou.aliyuncs.com/huanbaojia/icon_morentouxiang.png");
                    if (!createUserInfo(userInfo)) {
                        throw new LoginException("登录失败");
                    }
                }
                return userInfo;
            }
        }
        throw new LoginException("验证码错误");
    }

    @Override
    public UserInfo loginAppToken(String token) {
        logger.info("loginAppToken");
        UserInfo userInfo = null;
        try {
//            AppToken appToken = sysAppTokenMapper.getToken(token);
//            if (appToken != null) {
            SecretKey key = Keys.hmacShaKeyFor(Base64.getDecoder().decode(PropertiesFileLoader.getProperties("jwtsecret").getBytes()));
            Jwt jwt = Jwts.parser()
                    .setSigningKey(key)
                    .parse(token);
            Claims claims = (Claims) jwt.getBody();
            if (claims.getExpiration() != null) {
                if (claims.getExpiration().before(new Date())) {
                    return null;
                }
            }
            if (claims.getSubject().equals("guest")) {
                userInfo = new UserInfo();
            } else {
                userInfo = getUserInfoById(claims.getSubject());
            }
//            }
        } catch (Exception e) {
            logger.error("loginAppToken", e);
        }
        return userInfo;
    }

    @Override
    public List<String> findDepartLeader(String userId) {
        logger.info("findDepartLeader");
        try {
            return userInfoMapper.findDepartLeader(userId);
        } catch (Exception e) {
            logger.error("findDepartLeader", e);
        }
        return null;
    }

    @Override
    public List<String> findUserByRoleName(String roleName) {
        logger.info("findUserByRoleName");
        try {
            return userInfoMapper.findUserByRoleName(roleName);
        } catch (Exception e) {
            logger.error("findUserByRoleName", e);
        }
        return null;
    }

    public class LoginException extends Exception {
        public LoginException(String message) {
            super(message);
        }
    }

    @Override
    public UserInfo loginWechat(String code) {
        try {
            final String APP_ID = PropertiesFileLoader.getProperties("weixinappid");
            final String APP_SECRET = PropertiesFileLoader.getProperties("weixinsecret");

            String accessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APP_ID + "&secret=" + APP_SECRET + "&code=" + code
                    + "&grant_type=authorization_code";
            JSONObject data = WeixinUtil.loadJSON(accessTokenUrl);
            logger.debug("微信授权获取access_token：\n" + data.toString(4));
            String openId = data.getString("openid");
            String access_token = data.getString("access_token");

            String userDataUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + access_token + "&openid=" + openId;
            JSONObject userData = WeixinUtil.loadJSON(userDataUrl);
            logger.debug("微信授权获取用户信息：\n" + userData.toString(4));

            UserInfo userInfo = new UserInfo();
            userInfo.setOpenId(openId);
            userInfo = getUserInfo(userInfo);

            if (userInfo != null) {
                return userInfo;
            }
            userInfo = new UserInfo();
            userInfo.setOpenId(openId);
            String nickname = userData.getString("nickname");
            userInfo.setNickname(nickname);
            userInfo.setUsername(nickname);
            try {
                String country = userData.getString("country");
                userInfo.setCountry(country);
            } catch (JSONException ignored) {
            }
            try {
                String province = userData.getString("province");
                userInfo.setProvince(province);
            } catch (JSONException ignored) {
            }
            try {
                String city = userData.getString("city");
                userInfo.setCity(city);
            } catch (JSONException ignored) {
            }
            int sex = 1;
            try {
                sex = userData.getInt("sex");
            } catch (JSONException ignored) {
            }
            userInfo.setSex(sex == 1 ? "男" : "女");
            String headimgurl = null;
            try {
                headimgurl = userData.getString("headimgurl");
            } catch (JSONException ignored) {
            }
            userInfo.setIcon(saveAvatar(headimgurl));
            if (createUserInfo(userInfo)) {
                return userInfo;
            }
        } catch (Exception e) {
            logger.error("loginWechat", e);
        }
        return null;
    }

    private String saveAvatar(String url) {
        String path;
        HttpURLConnection httpUrl = null;
        URL iconUrl = null;
        try {
            iconUrl = new URL(url);
            httpUrl = (HttpURLConnection) iconUrl.openConnection();
            httpUrl.connect();

            Random random = new Random();
            StringBuilder randomCode = new StringBuilder();
            for (int i = 0; i < 8; i++) {
                randomCode.append(Integer.toString(random.nextInt(36), 36));
            }
            String uploadPath = String.format("images/%s-%s.jpg", new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss").format(new Date()), randomCode);
            path = ossFileService.upload(httpUrl.getInputStream(), uploadPath);
        } catch (IOException e) {
            path = "https://microball.oss-cn-hangzhou.aliyuncs.com/huanbaojia/icon_morentouxiang.png";
            e.printStackTrace();
        } finally {
            if (httpUrl != null) {
                httpUrl.disconnect();
            }
        }
        return path;
    }

    /**
     * <p>支付宝支付成功回调接口。充值</p>
     *
     * @param tradeNo
     * @param tradeStatus
     */
    @Override
    public void alipaySuccess(String tradeNo, String tradeStatus) {

        logger.info("alipaySuccess：支付宝支付成功回调接口 tradeNo：" + tradeNo + ", tradeStatus:" + tradeStatus);
        try {
            AlipayTemp alipayTemp = new AlipayTemp();
            alipayTemp.setOutTradeNo(tradeNo);
            alipayTemp = alipayTempMapper.queryAlipayTemp(alipayTemp);

            if (alipayTemp != null) {

                if (!AppConstant.Aliapi.TRADE_SUCCESS.equals(alipayTemp.getTradeStatus())) {

                    UserInfo userInfo = this.getUserInfoById(alipayTemp.getOrderId());
                    int cashPledge = userInfo.getCashPledge();
                    UserInfo updateUser = new UserInfo();
                    updateUser.setId(userInfo.getId());
                    updateUser.setCashPledge(cashPledge + alipayTemp.getTotalAmount().intValue());
                    if (userInfo.getApproveStep() == 3) {
                        //如果是交押金状态，更新为完成。
                        updateUser.setApproveStep(4);
                    }
                    this.updateUserInfo(updateUser);

                    alipayTemp.setTradeStatus(tradeStatus);

                    alipayTempMapper.updateByPrimaryKeySelective(alipayTemp);
                }

            }

        } catch (Exception e) {
            logger.error("alipaySuccess：支付宝支付成功回调接口异常 tradeNo：" + tradeNo + ", tradeStatus:" + tradeStatus, e);
        }

    }

}

