package com.yanzuoguang.cloud.helper;

import com.yanzuoguang.token.TokenHelper;
import com.yanzuoguang.util.exception.CodeException;
import com.yanzuoguang.util.helper.StringHelper;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * 获取Cookies对象
 *
 * @author 颜佐光
 */
public class CookiesHelper {
    /**
     * 单个Cookies最大长度
     */
    public static final int ITEM_MAX_SIZE = 1000;
    /**
     * 默认最大有效期
     */
    public static final int DEFAULT_MAX_AGE = 3 * 24 * 60 * 60;
    /**
     * 编码方式
     */
    public static final String CHARSET = "UTF-8";

    /**
     * Cookies标记格式
     */
    public static final String TAG_FORMAT = "%s_%d";

    /**
     * TOKEN缓存对象
     */
    public static final String TOKEN_STRING_KEY = "T_S";

    /**
     * 读取缓存Cookies
     *
     * @param key    键值
     * @param remove 读取后是否删除
     * @return 缓存的键值
     */
    public static String get(String key, boolean remove) throws UnsupportedEncodingException {
        HttpServletRequest request = getRequest();
        HttpServletResponse response = getResposne();
        if (request.getCookies() == null) {
            return StringHelper.EMPTY;
        }
        Map<String, String> map = new HashMap<>(request.getCookies().length);
        int keyLength = 0;

        // 遍历cookies找到对应的Cookies
        for (Cookie item : request.getCookies()) {
            String itemKey = item.getName();
            String itemValue = item.getValue();
            if (itemKey.equals(key)) {
                removeCookie(response, itemKey);
                if (StringHelper.isEmpty(itemValue)) {
                    return StringHelper.EMPTY;
                } else if (StringHelper.isNumber(itemValue)) {
                    keyLength = StringHelper.toInt(itemValue);
                    continue;
                } else {
                    return URLDecoder.decode(itemValue, CHARSET);
                }
            } else if (itemKey.startsWith(key)) {
                removeCookie(response, itemKey);
                map.put(itemKey, itemValue);
            }
        }

        // 循环处理多个Cookeis
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keyLength; i++) {
            String itemKey = String.format(TAG_FORMAT, key, i);
            if (!map.containsKey(itemKey)) {
                throw new CodeException("Cookies缺少[" + itemKey + "]");
            }
            sb.append(map.get(itemKey));
        }
        return URLDecoder.decode(sb.toString(), CHARSET);
    }

    /**
     * 写入缓存Cookies
     *
     * @param key   键
     * @param value 值
     */
    public static void set(String key, String value) throws UnsupportedEncodingException {
        HttpServletResponse response = getResposne();
        String toValue = URLEncoder.encode(value, CHARSET);
        if (toValue.length() < ITEM_MAX_SIZE) {
            addCookie(response, key, toValue);
        } else {
            int page = StringHelper.getPage(toValue.length(), ITEM_MAX_SIZE);
            // 总Cookies数量
            addCookie(response, key, String.valueOf(page));
            for (int i = 0; i < page; i++) {
                String itemKey = String.format(TAG_FORMAT, key, i);
                int start = i * ITEM_MAX_SIZE;
                int size = Math.min(toValue.length() - start, ITEM_MAX_SIZE);
                int end = start + size;
                String itemValue = toValue.substring(start, end);
                addCookie(response, itemKey, itemValue);
            }
        }
    }

    /**
     * 删除Cookie对象
     *
     * @param response 输出流
     * @param key      键值
     */
    private static void removeCookie(HttpServletResponse response, String key) {
        addCookie(response, key, StringHelper.EMPTY, 0);
    }

    /**
     * 添加Cookies缓存
     *
     * @param response 输出对象
     * @param key      键
     * @param value    值
     */
    private static void addCookie(HttpServletResponse response, String key, String value) {
        addCookie(response, key, value, DEFAULT_MAX_AGE);
    }

    /**
     * 添加Cookies缓存
     *
     * @param response 输出对象
     * @param key      键
     * @param value    值
     * @param maxAge   最大有效期
     */
    private static void addCookie(HttpServletResponse response, String key, String value, int maxAge) {
        // 创建cookie对象
        Cookie cookie = new Cookie(key, value);
        // 设置根目录生效
        cookie.setPath("/");
        cookie.setMaxAge(maxAge);
        // 服务器把cookie响应给客户端,所有的cookie对象,都会在服务器端创建,通过http响应给客户端(浏览器)
        response.addCookie(cookie);
    }

    /**
     * 获取请求对象
     *
     * @return Servlet请求对象
     */
    public static HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes())
                .getRequest();
        return request;
    }

    /**
     * 获取请求对象
     *
     * @return Servlet请求对象
     */
    public static HttpServletResponse getResposne() {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes())
                .getResponse();
        return response;
    }

    /**
     * 登录结束处理
     */
    public static void tokenFinish() throws UnsupportedEncodingException {
        String tokenResponse = TokenHelper.getTokenString();
        if (!StringHelper.isEmpty(tokenResponse)) {
            set(TOKEN_STRING_KEY, tokenResponse);
        }
        TokenHelper.remove();
    }

    /**
     * 登录初始化
     */
    public static void tokenInit() throws UnsupportedEncodingException {
        String tokenRequest = get(CookiesHelper.TOKEN_STRING_KEY, true);
        if (!StringHelper.isEmpty(tokenRequest)) {
            TokenHelper.setTokenString(tokenRequest);
        }
    }
}