package com.ruoyi.web.controller.jarvis;

import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.jarvis.domain.dto.WPS365TokenInfo;
import com.ruoyi.jarvis.service.IWPS365OAuthService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.RequestBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * WPS365 OAuth回调控制器
 * 用于处理OAuth回调，避免前端路由拦截
 * 
 * @author system
 */
@RestController
@RequestMapping("/wps365-callback")
public class WPS365CallbackController extends BaseController {
    
    private static final Logger log = LoggerFactory.getLogger(WPS365CallbackController.class);
    
    @Autowired
    private IWPS365OAuthService wps365OAuthService;
    
    /**
     * OAuth回调 - 通过授权码获取访问令牌（GET请求）
     * 路径：/wps365-callback
     * 注意：在WPS365开放平台只需配置域名：jarvis.van333.cn（不能包含路径）
     * 授权URL中的redirect_uri参数会自动使用配置中的完整URL：https://jarvis.van333.cn/wps365-callback
     */
    @Anonymous
    @GetMapping
    public ResponseEntity<?> oauthCallbackGet(@RequestParam(value = "code", required = false) String code, 
                                @RequestParam(value = "state", required = false) String state,
                                @RequestParam(value = "error", required = false) String error,
                                @RequestParam(value = "error_description", required = false) String errorDescription,
                                @RequestParam(value = "challenge", required = false) String challenge) {
        return handleOAuthCallback(code, state, error, errorDescription, challenge, null);
    }
    
    /**
     * OAuth回调 - 通过授权码获取访问令牌（POST请求）
     * WPS365在验证回调URL时会发送POST请求进行challenge验证
     * 支持application/json和application/x-www-form-urlencoded两种格式
     */
    @Anonymous
    @PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.TEXT_PLAIN_VALUE})
    public ResponseEntity<?> oauthCallbackPost(@RequestParam(value = "code", required = false) String code,
                                @RequestParam(value = "state", required = false) String state,
                                @RequestParam(value = "error", required = false) String error,
                                @RequestParam(value = "error_description", required = false) String errorDescription,
                                @RequestParam(value = "challenge", required = false) String challenge,
                                @RequestBody(required = false) String requestBody) {
        log.info("收到WPS365 POST回调请求 - code: {}, challenge: {}, requestBody: {}", 
            code != null ? "有" : "无", 
            challenge != null ? challenge : "无",
            requestBody != null && requestBody.length() > 0 ? requestBody.substring(0, Math.min(100, requestBody.length())) : "无");
        
        // 如果challenge在URL参数中，直接使用
        // 如果不在URL参数中，尝试从请求体中解析（可能是JSON或form-data）
        if (challenge == null && requestBody != null && !requestBody.trim().isEmpty()) {
            String bodyTrimmed = requestBody.trim();
            // 尝试解析JSON格式
            if (bodyTrimmed.startsWith("{")) {
                try {
                    com.alibaba.fastjson2.JSONObject json = com.alibaba.fastjson2.JSON.parseObject(requestBody);
                    if (json.containsKey("challenge")) {
                        challenge = json.getString("challenge");
                        log.info("从JSON请求体中解析到challenge: {}", challenge);
                    }
                } catch (Exception e) {
                    log.debug("解析JSON请求体失败", e);
                }
            }
            // 尝试解析form-urlencoded格式 (challenge=xxx)
            else if (bodyTrimmed.contains("challenge=")) {
                try {
                    String[] pairs = bodyTrimmed.split("&");
                    for (String pair : pairs) {
                        if (pair.startsWith("challenge=")) {
                            challenge = java.net.URLDecoder.decode(pair.substring("challenge=".length()), "UTF-8");
                            log.info("从form-urlencoded请求体中解析到challenge: {}", challenge);
                            break;
                        }
                    }
                } catch (Exception e) {
                    log.debug("解析form-urlencoded请求体失败", e);
                }
            }
            // 如果请求体就是challenge值本身（纯文本）
            else if (bodyTrimmed.length() < 200) {
                challenge = bodyTrimmed;
                log.info("将请求体作为challenge值: {}", challenge);
            }
        }
        
        return handleOAuthCallback(code, state, error, errorDescription, challenge, requestBody);
    }
    
    /**
     * 处理OAuth回调的核心逻辑
     */
    private ResponseEntity<?> handleOAuthCallback(String code, String state, String error, 
                                String errorDescription, String challenge, String requestBody) {
        try {
            // 处理challenge验证（WPS365后台配置时用于验证回调URL）
            if (challenge != null && !challenge.trim().isEmpty()) {
                log.info("收到WPS365 challenge验证请求 - challenge: {}", challenge);
                // 尝试返回JSON格式（符合OAuth标准）
                // 格式：{"challenge": "xxx"} 或直接返回challenge值
                try {
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.APPLICATION_JSON);
                    String jsonResponse = "{\"challenge\":\"" + challenge + "\"}";
                    return new ResponseEntity<>(jsonResponse, headers, HttpStatus.OK);
                } catch (Exception e) {
                    log.warn("返回JSON格式失败，尝试纯文本格式", e);
                    // 如果JSON失败，尝试纯文本
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.TEXT_PLAIN);
                    return new ResponseEntity<>(challenge, headers, HttpStatus.OK);
                }
            }
            
            // 处理授权错误
            if (error != null) {
                log.error("WPS365授权失败 - error: {}, error_description: {}", error, errorDescription);
                String errorMsg = errorDescription != null ? errorDescription : error;
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.TEXT_HTML);
                return new ResponseEntity<>(generateCallbackHtml(false, "授权失败: " + errorMsg, null), headers, HttpStatus.OK);
            }
            
            // 如果没有code也没有challenge，可能是直接访问，显示提示信息
            if (code == null || code.trim().isEmpty()) {
                log.warn("访问回调地址但没有授权码，可能是测试访问");
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.TEXT_HTML);
                return new ResponseEntity<>(generateCallbackHtml(false, "等待授权回调... 如果没有授权码，请通过授权流程访问", null), headers, HttpStatus.OK);
            }
            
            log.info("收到WPS365授权回调 - code: {}, state: {}", code, state);
            
            // 使用授权码换取access_token
            WPS365TokenInfo tokenInfo = wps365OAuthService.getAccessTokenByCode(code);
            
            // 验证返回的token信息
            if (tokenInfo == null || tokenInfo.getAccessToken() == null) {
                log.error("获取访问令牌失败 - tokenInfo: {}", tokenInfo);
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.TEXT_HTML);
                return new ResponseEntity<>(generateCallbackHtml(false, "获取访问令牌失败，响应数据格式不正确", null), headers, HttpStatus.OK);
            }
            
            log.info("成功获取访问令牌 - userId: {}, access_token: {}", 
                tokenInfo.getUserId(), 
                tokenInfo.getAccessToken() != null ? tokenInfo.getAccessToken().substring(0, 20) + "..." : "null");
            
            // 自动保存token到后端
            try {
                if (tokenInfo.getUserId() != null) {
                    wps365OAuthService.saveToken(tokenInfo.getUserId(), tokenInfo);
                    log.info("访问令牌已自动保存到后端缓存 - userId: {}", tokenInfo.getUserId());
                } else {
                    log.warn("userId为空，无法保存Token");
                    HttpHeaders headers = new HttpHeaders();
                    headers.setContentType(MediaType.TEXT_HTML);
                    return new ResponseEntity<>(generateCallbackHtml(false, "获取用户ID失败，无法保存Token", null), headers, HttpStatus.OK);
                }
            } catch (Exception e) {
                log.error("保存访问令牌失败", e);
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.TEXT_HTML);
                return new ResponseEntity<>(generateCallbackHtml(false, "保存访问令牌失败: " + e.getMessage(), null), headers, HttpStatus.OK);
            }
            
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.TEXT_HTML);
            return new ResponseEntity<>(generateCallbackHtml(true, "授权成功，访问令牌已自动保存", tokenInfo), headers, HttpStatus.OK);
        } catch (Exception e) {
            log.error("OAuth回调处理失败", e);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.TEXT_HTML);
            return new ResponseEntity<>(generateCallbackHtml(false, "授权失败: " + e.getMessage(), null), headers, HttpStatus.OK);
        }
    }
    
    /**
     * 生成回调HTML页面
     */
    private String generateCallbackHtml(boolean success, String message, WPS365TokenInfo tokenInfo) {
        StringBuilder html = new StringBuilder();
        html.append("<!DOCTYPE html>");
        html.append("<html lang='zh-CN'>");
        html.append("<head>");
        html.append("<meta charset='UTF-8'>");
        html.append("<meta name='viewport' content='width=device-width, initial-scale=1.0'>");
        html.append("<title>WPS365授权").append(success ? "成功" : "失败").append("</title>");
        html.append("<style>");
        html.append("body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; ");
        html.append("display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; ");
        html.append("background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }");
        html.append(".container { background: white; padding: 40px; border-radius: 10px; box-shadow: 0 10px 40px rgba(0,0,0,0.2); text-align: center; max-width: 500px; }");
        html.append(".icon { font-size: 64px; margin-bottom: 20px; }");
        html.append(".success { color: #52c41a; }");
        html.append(".error { color: #ff4d4f; }");
        html.append(".message { font-size: 16px; color: #333; margin-bottom: 20px; line-height: 1.6; }");
        html.append(".info { font-size: 14px; color: #666; margin-top: 20px; padding: 15px; background: #f5f5f5; border-radius: 5px; text-align: left; }");
        html.append("</style>");
        html.append("</head>");
        html.append("<body>");
        html.append("<div class='container'>");
        if (success) {
            html.append("<div class='icon success'>✓</div>");
            html.append("<h2 style='color: #52c41a; margin-bottom: 10px;'>授权成功</h2>");
        } else {
            html.append("<div class='icon error'>✗</div>");
            html.append("<h2 style='color: #ff4d4f; margin-bottom: 10px;'>授权失败</h2>");
        }
        html.append("<div class='message'>").append(message).append("</div>");
        
        // 显示Token信息（仅成功时）
        if (success && tokenInfo != null) {
            html.append("<div class='info'>");
            html.append("<strong>授权信息：</strong><br>");
            if (tokenInfo.getUserId() != null) {
                html.append("用户ID: ").append(tokenInfo.getUserId()).append("<br>");
            }
            if (tokenInfo.getExpiresIn() != null) {
                html.append("有效期: ").append(tokenInfo.getExpiresIn()).append(" 秒<br>");
            }
            html.append("</div>");
        }
        
        html.append("<p style='color: #999; font-size: 14px; margin-top: 20px;'>窗口将在3秒后自动关闭...</p>");
        html.append("</div>");
        html.append("<script>");
        html.append("// 通知父窗口授权结果");
        html.append("if (window.opener) {");
        html.append("  window.opener.postMessage({");
        html.append("    type: 'wps365_oauth_callback',");
        html.append("    success: ").append(success).append(",");
        html.append("    message: '").append(message.replace("'", "\\'").replace("\n", "\\n").replace("\r", "\\r")).append("'");
        if (success && tokenInfo != null && tokenInfo.getUserId() != null) {
            html.append(",");
            html.append("    userId: '").append(tokenInfo.getUserId()).append("'");
        }
        html.append("  }, '*');");
        html.append("}");
        html.append("// 3秒后自动关闭窗口");
        html.append("setTimeout(function() {");
        html.append("  if (window.opener) {");
        html.append("    window.close();");
        html.append("  } else {");
        html.append("    window.location.href = '/';");
        html.append("  }");
        html.append("}, 3000);");
        html.append("</script>");
        html.append("</body>");
        html.append("</html>");
        return html.toString();
    }
}

