package com.apobates.forum.member.storage.cookie;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.apobates.forum.member.entity.MemberGroupEnum;
import com.apobates.forum.member.entity.MemberRoleEnum;
import com.apobates.forum.member.entity.MemberStatusEnum;
import com.apobates.forum.member.storage.OnlineMemberStorage;
import com.apobates.forum.member.storage.core.MemberSessionBean;
import com.apobates.forum.member.storage.core.MemberSessionBeanConverter;
import com.apobates.forum.utils.Commons;
import com.apobates.forum.utils.CookieUtils;
import com.apobates.forum.utils.DateTimeUtils;
/**
 * 使用Cookie存储会员在线信息
 * 
 * @author xiaofanku
 * @since 20191231
 */
public abstract class OnlineMemberCookieStorage implements OnlineMemberStorage{
    private final CookieMetaConfig metaConfig;
    public final static String NP="-";
    private final static Logger logger = LoggerFactory.getLogger(OnlineMemberCookieStorage.class);
    
    public OnlineMemberCookieStorage(CookieMetaConfig metaConfig) {
        super();
        this.metaConfig = metaConfig;
    }
    
    @Override
    public void store(MemberSessionBean memberSessionBean, HttpServletRequest request, HttpServletResponse response) {
        //过期日期
        LocalDateTime expireDate = LocalDateTime.now().plusDays(1L);
        String memberSerialJSON = Commons.toJson(generateCookieMap(memberSessionBean, expireDate));
        String ss = new StorageSerialize(request.getParameter("token"), CookieUtils.encodeCookieValue(memberSerialJSON, NP)).toString();
        if (Commons.isNotBlank(ss)) {
            serializeCookie(ss, expireDate, request, response, metaConfig.getName(), metaConfig.getPath(), metaConfig.getDomain(), metaConfig.isHttps());
        }
    }
    @Override
    public void refresh(HttpServletRequest request, HttpServletResponse response, MemberStatusEnum status, MemberGroupEnum group, MemberRoleEnum role){
        Map<String,String> data = restoreMapForCookie(request);
        if(data.isEmpty()){
            return;
        }
        data.put("status", status.getSymbol()+"");
        data.put("group", group.getSymbol()+"");
        data.put("role", role.getSymbol()+"");
        //过期日期
        LocalDateTime expireDate = DateTimeUtils.parseDate(data.get("expire"));
        String memberSerialJSON = Commons.toJson(data);
        String ss = new StorageSerialize(Commons.optional(()->request.getParameter("token"), Commons.randomAlphaNumeric(8)), CookieUtils.encodeCookieValue(memberSerialJSON, NP)).toString();
        if (Commons.isNotBlank(ss)) {
            serializeCookie(ss, expireDate, request, response, metaConfig.getName(), metaConfig.getPath(), metaConfig.getDomain(), metaConfig.isHttps());
        }
    }
    @Override
    public void delete(HttpServletRequest request, HttpServletResponse response) {
        CookieMetaConfig cookieMeta = getMetaConfig();
        expireCookie(request, response, cookieMeta.getName(), cookieMeta.getPath(), cookieMeta.getDomain());
    }
    
    /**
     * 从请求携带的Cookie信息还原MemberSessionBean
     *
     * @param request Http请求对象
     * @return
     */
    @Override
    public Optional<MemberSessionBean> getInstance(HttpServletRequest request, String sentinel) {
        Map<String,String> data = restoreMapForCookie(request);
        return MemberSessionBeanConverter.toInstance(data, Commons.getRequestIp(request), sentinel);
    }
    /**
     * 从请求头的Cookie中还原Map结构
     * @param request
     * @return 
     */
    protected abstract Map<String, String> restoreMapForCookie(HttpServletRequest request);
    /**
     * 用实例生成Cookie中载荷的Map结构,不可变的Map
     * @param memberSessionBean
     * @param expireDate
     * @return 
     */
    protected abstract Map<String,String> generateCookieMap(MemberSessionBean memberSessionBean, LocalDateTime expireDate);
    
    /**
     * 返回Cookie配置信息
     *
     * @return
     */
    @Override
    public CookieMetaConfig getMetaConfig() {
        return metaConfig;
    }
    
    @Override
    public boolean isSupportRevival() {
        return true;
    }
    
    /**
     * 序列化会员信息到Cookie中
     * 
     * @param cookieValue cookie中保存的值
     * @param expireDateTime cookie到期的日期
     * @param request Http请求对象
     * @param response Http响应对象
     * @param cookieSymbol cookie的Key
     * @param cookiePath cookie的路径
     * @param cookieDomain cookie的域名
     * @param isHttps work on HTTPS/true,false work on http
     */
    protected void serializeCookie(
            String cookieValue, 
            LocalDateTime expireDateTime, 
            HttpServletRequest request, 
            HttpServletResponse response, 
            String cookieSymbol, 
            String cookiePath, 
            String cookieDomain, 
            boolean isHttps) {
        try {
            CookieUtils.serializeCookie(cookieValue, expireDateTime, request, response, cookieSymbol, cookiePath, cookieDomain, isHttps);
        } catch (IllegalStateException e) {
            if (logger.isDebugEnabled()) {
                logger.debug("[OM][CS]write cookie fail, reason: " + e.getMessage(), e);
            }
        }
    }
    
    /**
     * 清空Cookie中的会员信息
     *
     * @param request Http请求对象
     * @param response Http响应对象
     * @param cookieSymbol cookie的Key
     * @param cookiePath cookie的路径
     * @param cookieDomain cookie的域名
     */
    protected void expireCookie(
            HttpServletRequest request,
            HttpServletResponse response,
            String cookieSymbol,
            String cookiePath,
            String cookieDomain) {
        CookieUtils.expireCookie(request, response, cookieSymbol, cookiePath, cookieDomain);
    }
}
