package com.duiba.tuia.youtui.web.tool;

import cn.com.duiba.wolf.perf.timeprofile.DBTimeProfile;
import cn.com.duiba.wolf.utils.SecurityUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.duiba.tuia.youtui.web.constant.Constants;
import com.duiba.tuia.youtui.web.constant.Constants.COOKIEKEY;
import com.duiba.tuia.youtui.web.model.RequestParams;
import com.duiba.tuia.youtui.web.model.UserAccount;
import com.duiba.tuia.youtui.web.service.TokenService;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Map;

/**
 * The Class RequestLocal.
 */
public class RequestLocal {

    /** The logger. */
    private Logger                           logger             = LoggerFactory.getLogger(RequestLocal.class);

    /** 一天的毫秒数. */
    private static final int                 DAY_OF_MILLISECOND = 86400000;

    /** The local. */
    private static ThreadLocal<RequestLocal> local              = new ThreadLocal<>();

    /** The request params. */
    private RequestParams                    requestParams;

    /** 用户ID. */
    private Long                             cId;

    /** 用户ID. */
    private Long                             appId;

    /** 用户tokenID */
    private String                           tokenId;

    /** The deap. */
    private String                           deap;

    /** 用户ID. */
    private UserAccount                      userAccount;

    /** cookie中的账户内容. */
    private JSONObject                       accountInfo;

    /** The request. */
    private HttpServletRequest               request;

    /** The response. */
    private HttpServletResponse              response;
    
    /** The response cookies. */
    private Map<String,String>               responseCookies;

    private static TokenService tokenService;

    /** 虚拟奖品-第三方userid **/
    private String userId;

    /**
     * The Constructor.
     */
    private RequestLocal() {
    }

    /**
     * Gets the.
     *
     * @return the request local
     */
    public static RequestLocal get() {
        RequestLocal rl = local.get();
        if (rl == null) {
            rl = new RequestLocal();
            local.set(rl);
        }
        return rl;
    }
    
    public Map<String,String> getCollParams(){
        Map<String,String> map = Maps.newHashMap();
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if(cookie.getName().startsWith("_coll")){
                    map.put(cookie.getName(), cookie.getValue());
                }
            }
        }
        return map;
    }

    /**
     * Clear.
     */
    public static void clear() {
        local.set(null);
    }

    /**
     * 根据key获取cookie中对应的值.<br>
     * 如果cookie为空或者不存在改key则返回null<br>
     *
     * @param key 键
     * @return cookie中对应的值
     */
    private String getCookie(String key) {
        if(null != getResponseCookies() && null != getResponseCookies().get(key)){
           return getResponseCookies().get(key);
        }
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (key.equals(cookie.getName())) {
                    String value = cookie.getValue();
                    if (StringUtils.isNotBlank(value)) {
                        return value;
                    }
                }
            }
        }

        return null;
    }

    /**
     * 获取Cookie中sloid.
     *
     * @return the slot id
     */
    public String getSlotId()
    {
        return getCookie("_coll_slot");
    }


    /**
     * 根据app ID获取Cookie中sloid.
     *
     * @return the slot id
     */
    public String getSlotIdByAppId(Long appId)
    {
        return getCookie("_coll_"+appId+"_slot");
    }
    
    /**
     * 获取Cookie中deviceId.
     *
     * @return the slot id
     */
    public String getDeviceId()
    {
        return getCookie("_coll_device");
    }

    /**
     * 获取Cookie中userId.
     *
     * @return the userid
     */
    public String getUserId()
    {
        return getCookie("_coll_userId");
    }

    /**
     * 获取Cookie中userId.
     *
     * @return the userid
     */
    public String getAppKey()
    {
        return getCookie(Constants.APP_KEY);
    }

    /**
     * getConsumerFormToken:(这里用一句话描述这个方法的作用). <br/>
     *
     * @return
     * @since JDK 1.6
     */
    public String getConsumerFormToken() {
        try {
            DBTimeProfile.enter("formTokenService.getConsumerToken");
            return tokenService.getConsumerTokenFromCache(getCid());
        } finally {
            DBTimeProfile.release();
        }
    }
    
    /**
     * 获取cookie中关于账号信息部分的数据.
     *
     * @return the cookie value
     */
    private JSONObject getAccountInfo() {
        if (accountInfo == null) {
            try {
                // 获取账号信息
                String accound = getCookie(COOKIEKEY.COOKIE_KEY);
                if (accound != null) {
                    String content = SecureTool.decryptConsumerCookie(accound);
                    if (StringUtils.isNotBlank(content)) {
                        JSONObject json = JSON.parseObject(content);
                            accountInfo = json;
                    }
                }
            } catch (Exception e) {
                CookieUtil.deleteWildcardCookie(COOKIEKEY.ACCOUNT_KEY);
                logger.info("parse cookie happen error . this error IP = "+local.get().getIp()+" and error slotId = "+local.get().getSlotId(), e);
            }
        }
        return accountInfo;
    }
    
    /**
     * Sets the account info.
     *
     * @param accountInfo the account info
     */
    public void setAccountInfo(JSONObject accountInfo) {
        this.accountInfo = accountInfo;
    }

    /**
     * 得到当前登录用户ID.
     *
     * @return the user id
     */
    public Long getCid() {
        if (cId == null && getAccountInfo() != null) {
            cId = accountInfo.getLong(COOKIEKEY.ACCOUNT_ID_KEY);
        }
        return cId;
    }

    /**
     * 得到当前登录用户ID.
     *
     * @return the user id
     */
    public boolean getLoginStatus() {
        if (getUserAccount() != null) {
            return getUserAccount().getLoginStatus();
        }
        return false;
    }
    
    /**
     * Setc id.
     *
     * @param cId the c id
     */
    public void setcId(Long cId) {
        this.cId = cId;
    }

    public String getTokenId(){
        if (tokenId == null) {
            tokenId = getCookie(COOKIEKEY.TOKEN_ID_COOKIE);
        }
        return tokenId;
    }

    /**
     * Setc tokenId.
     *
     * @param tokenId the c tokenId
     */
    public void setTokenId(String tokenId) {
        this.tokenId = tokenId;
    }



    /**
     * Gets the app id.
     *
     * @return the app id
     */
    public Long getAppId() {
        if (appId == null && getAccountInfo() != null) {
            appId = accountInfo.getLong(COOKIEKEY.APP_ID_KEY);
        }
        return appId;
    }
    
    
    /**
     * Sets the app id.
     *
     * @param appId the app id
     */
    public void setAppId(Long appId) {
        this.appId = appId;
    }

    /**
     * Gets the user account.
     *
     * @return the user account
     */
    public UserAccount getUserAccount() {
        if (userAccount == null && getAccountInfo() != null) {
            userAccount = JSON.parseObject(accountInfo.get(COOKIEKEY.ACCOUNT_KEY).toString(), UserAccount.class);
        }
        return userAccount;
    }
    
    
    /**
     * Sets the user account.
     *
     * @param userAccount the user account
     */
    public void setUserAccount(UserAccount userAccount) {
        this.userAccount = userAccount;
    }

    /**
     * getIp:(这里用一句话描述这个方法的作用). <br/>
     *
     * @return the ip
     * @since JDK 1.6
     */
    public String getIp() {
        return RequestTool.getIpAddr(getRequest());
    }

    /**
     * getOs:(这里用一句话描述这个方法的作用). <br/>
     *
     * @return the os
     * @since JDK 1.6
     */
    public String getOs() {
        return cn.com.duiba.wolf.perf.timeprofile.RequestTool.getOSNew(getRequest());
    }

    /**
     * Gets the cid cookie.
     *
     * @return the cid cookie
     */
    public String getCidCookie() {
        return getCookie(Constants.COOKIEKEY.COOKIE_KEY);
    }

    /**
     * Gets the deap.
     *
     * @return the deap
     */
    public String getDeap() {
        if (StringUtils.isNotBlank(deap)) {
            return deap;
        }

        try {
            String mdeap = getCookie("deap");
            if (StringUtils.isBlank(mdeap)) {
                return deap;
            }

            String[] deaps = mdeap.split(",");
            for (String requestStr : deaps) {
                if (requestStr.startsWith(userAccount.getAppId().toString())) {
                    return requestStr;
                }
            }
        } catch (Exception e) {
            logger.error("", e);
            CookieUtil.deleteWildcardCookie("deap");
        }

        return deap;
    }
    
    
    /**
     * setCookie:set cookie信息. <br/>
     *
     * @author cdm
     * @param userAccount:用户信息
     * @since JDK 1.7
     */
    public void setCookie(UserAccount userAccount) {

        // build user Account JsonObject
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(COOKIEKEY.LOGIN_TIME_KEY, new Date().getTime());// 加入time使每次加密字符串都不同，且24小时后过期
        jsonObject.put(COOKIEKEY.ACCOUNT_ID_KEY, userAccount.getUserId());
        jsonObject.put(COOKIEKEY.APP_ID_KEY, userAccount.getAppId());
        jsonObject.put(COOKIEKEY.ACCOUNT_KEY, userAccount);

        String envalue = SecureTool.encryptConsumerCookie(jsonObject.toJSONString());

        // 植入appId和用户id，nginx可以获取该字段
        JSONObject aidCidObject = new JSONObject();
        aidCidObject.put(COOKIEKEY.APP_ID_KEY, userAccount.getAppId());
        aidCidObject.put(COOKIEKEY.ACCOUNT_ID_KEY, userAccount.getUserId());

        String aidCidValue = SecurityUtils.encode2StringByBase64(aidCidObject.toJSONString().getBytes());
        
        CookieUtil.setCrossCookieForEvery(COOKIEKEY.COOKIE_KEY, envalue);
        CookieUtil.setCrossCookieForEvery(COOKIEKEY.ACCESS_LOG_KEY, aidCidValue);

        String tokenId = SecurityUtils.encode2StringByMd5(JSONObject.toJSONString(userAccount));
        CookieUtil.setCrossCookieForEvery(COOKIEKEY.TOKEN_ID_COOKIE, tokenId);

        
        //response
        this.setAccountInfo(jsonObject);
        this.setAppId(userAccount.getAppId());
        this.setcId(userAccount.getUserId());
        this.setUserAccount(userAccount);
        this.setTokenId(tokenId);
        Map<String,String> resMap = Maps.newHashMap();
        resMap.put(COOKIEKEY.COOKIE_KEY, envalue);
        resMap.put(COOKIEKEY.ACCESS_LOG_KEY, aidCidValue);
        resMap.put(COOKIEKEY.TOKEN_ID_COOKIE, tokenId);
        this.setResponseCookies(resMap);
    }

    /**
     * getRequestParams:(这里用一句话描述这个方法的作用). <br/>
     *
     * @return the request params
     * @since JDK 1.6
     */
    public RequestParams getRequestParams() {
        return this.requestParams;
    }

    /**
     * Gets the request.
     *
     * @return the request
     */
    public HttpServletRequest getRequest() {
        return request;
    }

    /**
     * Sets the request.
     *
     * @param request the request
     */
    public void setRequest(HttpServletRequest request) {
        this.request = request;
        this.requestParams = RequestParams.parse(request, getCid());
    }

    /**
     * Gets the response.
     *
     * @return the response
     */
    public HttpServletResponse getResponse() {
        return response;
    }

    /**
     * Sets the response.
     *
     * @param response the response
     */
    public void setResponse(HttpServletResponse response) {
        this.response = response;
    }

    
    /**
     * Gets the response cookies.
     *
     * @return the response cookies
     */
    public Map<String, String> getResponseCookies() {
        return responseCookies;
    }

    
    /**
     * Sets the response cookies.
     *
     * @param responseCookies the response cookies
     */
    public void setResponseCookies(Map<String, String> responseCookies) {
        this.responseCookies = responseCookies;
    }

}
