package com.infoepoch.pms.agent.service.auth;

import com.infoepoch.pms.agent.common.utils.component.RedisTool;
import com.infoepoch.pms.agent.config.JsonUtils;
import com.infoepoch.pms.agent.platform.shared.exception.BusinessException;
import com.infoepoch.pms.agent.platform.shared.response.ResultCode;
import com.infoepoch.pms.agent.properties.SsoProperties;
import com.infoepoch.pms.agent.service.auth.dto.LoginSessionUser;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 登录会话管理服务。
 * <p>
 * 负责会话 Cookie 操作和 Redis 会话存储。
 * </p>
 */
@Service
@RequiredArgsConstructor
public class LoginSessionService {

    private static final String SESSION_KEY_PREFIX = "pms-agent:session:";

    private final RedisTool redisTool;
    private final SsoProperties ssoProperties;

    /**
     * 创建登录会话，生成 Session ID 写入 Redis 并设置 Cookie。
     *
     * @param user     登录用户信息
     * @param response HTTP 响应
     */
    public void createLoginSession(LoginSessionUser user, HttpServletResponse response) {
        String sessionId = UUID.randomUUID().toString().replace("-", "");
        redisTool.put(SESSION_KEY_PREFIX + sessionId, user, ssoProperties.getSessionTtlSeconds(), TimeUnit.SECONDS);
        addCookie(response, ssoProperties.getSessionCookieName(), sessionId, ssoProperties.getSessionTtlSeconds());
    }

    /**
     * 从请求的 Session Cookie 中获取当前登录用户。
     *
     * @param request HTTP 请求
     * @return 登录用户信息
     * @throws BusinessException 会话不存在或已过期时
     */
    public LoginSessionUser getCurrentUser(HttpServletRequest request) {
        String sessionId = getCookieValue(request, ssoProperties.getSessionCookieName());
        if (StringUtils.isBlank(sessionId)) {
            throw new BusinessException(ResultCode.UNAUTHORIZED, "当前登录会话不存在或已过期");
        }
        LoginSessionUser user = redisTool.get(SESSION_KEY_PREFIX + sessionId);
        if (user == null) {
            throw new BusinessException(ResultCode.UNAUTHORIZED, "当前登录会话不存在或已过期");
        }
        return user;
    }

    /**
     * 清除客户端 SSO Token Cookie。
     *
     * @param response HTTP 响应
     */
    public void clearSsoCookie(HttpServletResponse response) {
        addCookie(response, ssoProperties.getCookieName(), "", 0);
    }

    /**
     * 清除当前登录会话和客户端 Session Cookie。
     *
     * @param request  HTTP 请求
     * @param response HTTP 响应
     */
    public void clearLoginSession(HttpServletRequest request, HttpServletResponse response) {
        String sessionId = getCookieValue(request, ssoProperties.getSessionCookieName());
        if (StringUtils.isNotBlank(sessionId)) {
            redisTool.remove(SESSION_KEY_PREFIX + sessionId);
        }
        addCookie(response, ssoProperties.getSessionCookieName(), "", 0);
    }

    /**
     * 从请求中获取指定名称的 Cookie 值。优先从 Cookie 数组获取，若为空则回退到解析 Header。
     *
     * @param request HTTP 请求
     * @param name    Cookie 名称
     * @return Cookie 值，不存在时返回 null
     */
    public String getCookieValue(HttpServletRequest request, String name) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (name.equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }
        String cookieHeader = request.getHeader("Cookie");
        if (StringUtils.isBlank(cookieHeader)) {
            return null;
        }
        String[] pairs = cookieHeader.split(";");
        for (String pair : pairs) {
            String[] parts = pair.trim().split("=", 2);
            if (parts.length == 2 && name.equals(parts[0])) {
                return parts[1];
            }
        }
        return null;
    }

    /**
     * 构造并设置 Cookie 响应头。
     *
     * @param response      HTTP 响应
     * @param name          Cookie 名称
     * @param value         Cookie 值
     * @param maxAgeSeconds Cookie 最大有效秒数
     */
    private void addCookie(HttpServletResponse response, String name, String value, long maxAgeSeconds) {
        StringBuilder cookie = new StringBuilder();
        cookie.append(name).append("=").append(value == null ? "" : value)
                .append("; Path=/")
                .append("; Max-Age=").append(maxAgeSeconds)
                .append("; HttpOnly")
                .append("; SameSite=Lax");
        if (ssoProperties.isSecureCookie()) {
            cookie.append("; Secure");
        }
        response.addHeader("Set-Cookie", cookie.toString());
    }
}
