package com.infoepoch.pms.agent.controller;

import com.infoepoch.pms.agent.common.utils.Base64Utils;
import com.infoepoch.pms.agent.common.utils.SnowFlake;
import com.infoepoch.pms.agent.config.JsonUtils;
import com.infoepoch.pms.agent.domain.baisc.user.UserLoginType;
import com.infoepoch.pms.agent.platform.shared.exception.BusinessException;
import com.infoepoch.pms.agent.platform.shared.exception.ValidationException;
import com.infoepoch.pms.agent.platform.shared.response.Result;
import com.infoepoch.pms.agent.platform.shared.response.ResultCode;
import com.infoepoch.pms.agent.properties.SsoProperties;
import com.infoepoch.pms.agent.service.auth.ExternalSsoTokenVerifier;
import com.infoepoch.pms.agent.service.auth.LoginSessionService;
import com.infoepoch.pms.agent.service.auth.TargetUserService;
import com.infoepoch.pms.agent.service.auth.dto.ExternalSsoUser;
import com.infoepoch.pms.agent.service.auth.dto.LoginSessionUser;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 外部系统单点登录控制器。
 * <p>
 * 负责处理 SSO Token 验证、登录会话创建及当前用户查询。
 * </p>
 */
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class ExternalSsoController {

    private static final String DEFAULT_REDIRECT = "/pms-agent/";

    private final ExternalSsoTokenVerifier tokenVerifier;
    private final TargetUserService targetUserService;
    private final LoginSessionService loginSessionService;
    private final SsoProperties ssoProperties;

    /**
     * 外部系统单点登录入口。
     * <p>
     * 从 Cookie 中提取 SSO Token 进行验证，匹配目标系统用户后创建登录会话，
     * 清除 SSO Cookie 并重定向到指定页面。
     * </p>
     *
     * @param redirect 登录后重定向路径，为空时使用默认路径
     * @param request  HTTP 请求
     * @param response HTTP 响应
     * @throws IOException 重定向失败时
     */
    @GetMapping("/external-sso")
    public void externalSso(@RequestParam(required = false) String redirect,
                            HttpServletRequest request,
                            HttpServletResponse response) throws IOException {
        String token = loginSessionService.getCookieValue(request, ssoProperties.getCookieName());
        if (StringUtils.isBlank(token)) {
            throw new BusinessException(ResultCode.PARAM_ERROR,
                    "单点登录失败，缺少 " + ssoProperties.getCookieName());
        }

        ExternalSsoUser ssoUser = tokenVerifier.verify(token);
        LoginSessionUser loginUser = targetUserService.findLoginSessionUser(ssoUser.getUsername());
        loginSessionService.createLoginSession(loginUser, response);
        loginSessionService.clearSsoCookie(response);
        response.sendRedirect(normalizeRedirect(redirect));
    }

    /**
     * 获取当前登录用户信息。
     *
     * @param request HTTP 请求
     * @return 当前登录用户
     */
    @GetMapping("/current-user")
    public Result<LoginSessionUser> currentUser(HttpServletRequest request) {
        return Result.success(loginSessionService.getCurrentUser(request));
    }

    /**
     * 退出当前系统登录会话。
     *
     * @param request  HTTP 请求
     * @param response HTTP 响应
     * @return 退出结果
     */
    @PostMapping("/logout")
    public Result<Void> logout(HttpServletRequest request, HttpServletResponse response) {
        loginSessionService.clearLoginSession(request, response);
        return Result.success(null);
    }

    /**
     * 校验并规范化重定向地址，防止开放重定向攻击。不安全的地址回退到默认路径。
     *
     * @param redirect 原始重定向地址
     * @return 安全的规范化路径
     */
    private String normalizeRedirect(String redirect) {
        if (StringUtils.isBlank(redirect)) {
            return DEFAULT_REDIRECT;
        }
        try {
            if (redirect.contains("\\") || redirect.startsWith("//")) {
                return DEFAULT_REDIRECT;
            }
            String decoded = URLDecoder.decode(redirect, StandardCharsets.UTF_8);
            if (decoded.contains("\\") || decoded.startsWith("//")) {
                return DEFAULT_REDIRECT;
            }
            URI uri = URI.create(decoded).normalize();
            if (uri.isAbsolute() || uri.getRawAuthority() != null) {
                return DEFAULT_REDIRECT;
            }
            String path = uri.getPath();
            if ("/pms-agent".equals(path) || path.startsWith("/pms-agent/")) {
                return uri.getRawQuery() == null ? path : path + "?" + uri.getRawQuery();
            }
            return DEFAULT_REDIRECT;
        } catch (Exception ex) {
            return DEFAULT_REDIRECT;
        }
    }
}
