/*
 *
 * Copyright (c) 2001-2017 泛微软件.
 * 泛微协同商务系统,版权所有.
 *
 */
package com.cloudstore.dev.api.service;


import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cloudstore.dev.api.bean.OtherSystemInfo;
import com.cloudstore.dev.api.util.AuthManager;
import com.cloudstore.eccom.common.WeaIndexManager;
import com.cloudstore.eccom.result.WeaResultMsg;
import com.cloudstore.mobile.constant.AuthTypeConstant;
import com.cloudstore.mobile.sso.auth.AuthTokenBean;
import com.cloudstore.mobile.sso.util.TokenStore;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import weaver.conn.RecordSet;
import weaver.general.BaseBean;
import weaver.general.Util;
import weaver.rsa.security.Base64;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;

import java.security.*;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 简单版本认证管理接口,适用于Restful Api调用
 *
 * @author AndyZhang
 */
@Path("/ec/dev/auth")
public class ServiceAuth {

    private static final Log logger = LogFactory.getLog(ServiceAuth.class);

    @POST
    @Path("/regist")
    @Produces(MediaType.TEXT_PLAIN)
    public String AuthRegist(@Context HttpServletRequest request, @Context HttpServletResponse response) {
        WeaResultMsg result = new WeaResultMsg(false);
        if (AuthManager.allowIp(request)) {
            String appid = request.getHeader(AuthManager.appid);
            String cpk = request.getHeader(AuthManager.cpk);
            OtherSystemInfo info = AuthManager.getAppInfo(appid);
            String secret = null, publicKey = null;
            if (StringUtils.isNotBlank(info.getAppid())) {
                if(StringUtils.isBlank(info.getServerPrivateKey()) && StringUtils.isBlank(info.getServerPublicKey())){
                    // 防止并发重复调用，只生成一次以后都用这个
                    synchronized (ServiceAuth.class){
                        // 这里只判断publickey是因为减少计算，KeyPair生成时会向数据库自动写入密钥对，只返回给前端publickey，无需生成privatekey，也无需判断privatekey是否存在
                        if(StringUtils.isBlank(info.getServerPublicKey())){
                            try {
                                KeyPair keyPair = SecureUtil.generateKeyPair("RSA/ECB/PKCS1Padding",2048);
                                secret = AuthManager.updateSecret(appid, cpk, keyPair);
                                // 重复执行了Base64编码
                                publicKey = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
                                info.setServerPublicKey(publicKey);
                                info.setSecret(secret);
                            }catch (Throwable e){
                                e.printStackTrace();
                            }
                        }
                    }
                }
                // 如果盐值存在，直接获取盐值
                secret = info.getSecret();
                publicKey = info.getServerPublicKey();
//                }else{
//                    // 生成密钥对和随机盐值
//                    KeyPair keyPair = SecureUtil.generateKeyPair("RSA/ECB/PKCS1Padding",2048);
//                    secret = AuthManager.updateSecret(appid, cpk, keyPair);
//                    publicKey = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
                result.put("secrit", secret);//兼容老版本名字输出错误
                result.put("secret", secret);
                result.put("spk", publicKey);
                logger.info("返回spk::"+publicKey+" 返回secret::"+secret);
                logger.info("Api Server regist集成注册成功.");
                return result.success("ok").toString();
            } else {
                result.put("errcode", "1");
                logger.error("注册失败没有在找到正确的APPID:" + appid);
                return result.fail(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004758,weaver.general.ThreadVarLanguage.getLang())+"APPID:" + appid).toString();
            }
        }
        logger.error("非法ip请求:"+Util.getIpAddr(request));
        return result.fail(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004759,weaver.general.ThreadVarLanguage.getLang())+"ip"+weaver.systeminfo.SystemEnv.getHtmlLabelName(648,weaver.general.ThreadVarLanguage.getLang())+"").toString();
    }

    @POST
    @Path("/regist/update")
    @Produces(MediaType.TEXT_PLAIN)
    public String AuthUpdate(@Context HttpServletRequest request, @Context HttpServletResponse response) {
        WeaResultMsg result = new WeaResultMsg(false);
        if (AuthManager.allowIp(request)) {
            String appid = request.getHeader(AuthManager.appid);
            String cpk = request.getHeader(AuthManager.cpk);
            OtherSystemInfo info = AuthManager.getAppInfo(appid);
            if (StringUtils.isNotBlank(info.getAppid())) {
                // 生成密钥对和随机盐值
                KeyPair keyPair = SecureUtil.generateKeyPair("RSA/ECB/PKCS1Padding",2048);
                String secret = AuthManager.updateSecret(appid, cpk, keyPair);
                String publicKey = Base64.encodeBase64String(keyPair.getPublic().getEncoded());
                result.put("secrit", secret);//兼容老版本名字输出错误
                result.put("secret", secret);
                result.put("spk", publicKey);
                logger.info("Api Server update集成注册成功.");
                return result.success("ok").toString();
            } else {
                result.put("errcode", "1");
                logger.error("注册失败没有在找到正确的APPID:" + appid);
                return result.fail(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004758,weaver.general.ThreadVarLanguage.getLang())+"APPID:" + appid).toString();
            }
        }
        logger.error("非法ip请求:"+Util.getIpAddr(request));
        return result.fail(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004759,weaver.general.ThreadVarLanguage.getLang())+"ip"+weaver.systeminfo.SystemEnv.getHtmlLabelName(648,weaver.general.ThreadVarLanguage.getLang())+"").toString();
    }

    @POST
    @Path("/applytoken")
    @Produces(MediaType.TEXT_PLAIN)
    public String AuthToken(@Context HttpServletRequest request, @Context HttpServletResponse response) {
        WeaResultMsg result = new WeaResultMsg(false);
        if (AuthManager.allowIp(request)) {
            String appid = request.getHeader("appid");
            String secret = request.getHeader("secret");
//            logger.info("appid:"+appid+" 解密前secret:"+secret);
            int time = Util.getIntValue(request.getHeader("time"),30*60);
            OtherSystemInfo info = AuthManager.getAppInfo(appid);
//            if (StringUtils.isNotBlank(info.getServerPrivateKey()) && StringUtils.isNotBlank(info.getServerPublicKey())) {
//                try {
//                    RSA rsa = new RSA(info.getServerPrivateKey(), info.getServerPublicKey());
////                    logger.info("spk::"+info.getServerPublicKey()+"\nprivatekey::"+info.getServerPrivateKey());
//                    secret = StrUtil.str(rsa.decrypt(secret, KeyType.PrivateKey), CharsetUtil.CHARSET_UTF_8);
//                }catch (Exception e){
//                    e.printStackTrace();
////                    logger.info("appid:"+appid+" 异常secret:"+secret);
//                    return result.fail("secret"+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004760,weaver.general.ThreadVarLanguage.getLang())+","+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004761,weaver.general.ThreadVarLanguage.getLang())+".").toString();
//                }finally {
////                    logger.info("appid:"+appid+" 解密后secret:"+secret);
//                }
//            } else {
//                try {
//                    weaver.rsa.security.RSA rsa = new weaver.rsa.security.RSA();
//                    secret = rsa.decrypt(null, secret, true);
//                }catch (Exception th){
//                    logger.error("info::"+ JSON.toJSONString(info) + " appid::"+appid);
//                    th.printStackTrace();
//                }
//            }

            BaseBean bb = new BaseBean();
            if (StringUtils.isNotBlank(info.getServerPrivateKey()) && StringUtils.isNotBlank(info.getServerPublicKey())) {
                try {
                    RSA rsa = new RSA(info.getServerPrivateKey(), info.getServerPublicKey());
                    String secret2 = StrUtil.str(rsa.decrypt(secret, KeyType.PrivateKey), CharsetUtil.CHARSET_UTF_8);
                    bb.writeLog("secret2:"+secret2);
                }catch (Exception e){
                    e.printStackTrace();
//                    logger.info("appid:"+appid+" 异常secret:"+secret);
                    bb.writeLog("e:"+e);
                    return result.fail("secret"+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004760,weaver.general.ThreadVarLanguage.getLang())+","+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004761,weaver.general.ThreadVarLanguage.getLang())+".").toString();
                }finally {
//                    logger.info("appid:"+appid+" 解密后secret:"+secret);
                }
            }

            try {
                weaver.rsa.security.RSA rsa = new weaver.rsa.security.RSA();
                String secret3 = rsa.decrypt(null, secret, true);
                bb.writeLog("secret3:"+secret3);
            }catch (Exception th){
                th.printStackTrace();
                bb.writeLog("th::"+ th);
            }

            try {
                if (StringUtils.isBlank(secret))
                    return result.fail("secret"+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004760,weaver.general.ThreadVarLanguage.getLang())+","+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004761,weaver.general.ThreadVarLanguage.getLang())+".").toString();
                if (secret.equalsIgnoreCase(info.getSecret())) {

                    String token = generateAccessToken(appid, time);
                    result.put("token", token);
                    result.success(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(512751,weaver.general.ThreadVarLanguage.getLang())+"!");
                    logger.info("success getToken :"+token);
                } else {
                    logger.info("1004762 secret:"+secret+" appid:"+appid+" info:"+JSON.toJSONString(info));
                    result.fail(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004762,weaver.general.ThreadVarLanguage.getLang())+"");
                }
            } catch (Exception e) {
                e.printStackTrace();
                result.fail(e.getMessage());
            }
        } else {
            logger.error("非法ip请求:"+Util.getIpAddr(request));
            result.fail(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10004759,weaver.general.ThreadVarLanguage.getLang())+"ip"+weaver.systeminfo.SystemEnv.getHtmlLabelName(648,weaver.general.ThreadVarLanguage.getLang())+"");
        }
        return result.toString();
    }

    public String generateAccessToken(Object msg,int second){
//        String accessToekn = String.valueOf(SnowFlakeFactory.getInstance(this.getClass(), 0, 0, 0).nextId());
//        System.out.println(accessToekn);
        String accessToekn = WeaIndexManager.getGuid();

        AuthTokenBean token = new AuthTokenBean();
        token.setUuid(accessToekn);
        token.setMsg(msg);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.SECOND,second);
        token.setExpireTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(calendar.getTime()));
        token.setType(AuthTypeConstant.ACCESS_TOKEN_TYPE);

        storeToken2DB(token);
        return accessToekn;
    }

    /**
     * Token信息保存至数据库
     */
    private void storeToken2DB(AuthTokenBean bean){
        RecordSet rs = new RecordSet();
        String sql = "insert into ecology_mobile_token(uuid,auth_type,expire_time,msg) values(?,?,?,?)";
        rs.executeUpdate(sql,bean.getUuid(),bean.getType(),bean.getExpireTime(),JSONObject.toJSONString(bean.getMsg()));
    }
}
