package com.ruoyi.jarvis.util;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

/**
 * 腾讯文档API工具类
 * 
 * @author system
 */
public class TencentDocApiUtil {
    
    private static final Logger log = LoggerFactory.getLogger(TencentDocApiUtil.class);
    
    // 静态初始化块：禁用系统代理，确保腾讯文档API调用直接连接
    static {
        System.setProperty("java.net.useSystemProxies", "false");
        // 清除可能存在的代理设置
        System.clearProperty("http.proxyHost");
        System.clearProperty("http.proxyPort");
        System.clearProperty("https.proxyHost");
        System.clearProperty("https.proxyPort");
        log.info("已禁用系统代理设置，腾讯文档API将直接连接");
    }
    
    /**
     * 获取访问令牌
     * 
     * @param appId 应用ID
     * @param appSecret 应用密钥
     * @param code 授权码
     * @param redirectUri 回调地址
     * @return 包含access_token和refresh_token的JSON对象
     */
    public static JSONObject getAccessToken(String appId, String appSecret, String code, String redirectUri, String tokenUrl) {
        try {
            // 构建请求参数
            StringBuilder params = new StringBuilder();
            params.append("grant_type=authorization_code");
            params.append("&client_id=").append(appId);
            params.append("&client_secret=").append(appSecret);
            params.append("&code=").append(code);
            params.append("&redirect_uri=").append(java.net.URLEncoder.encode(redirectUri, "UTF-8"));
            
            // 直接使用HttpURLConnection，不使用代理，避免被nginx拦截
            URL url = new URL(tokenUrl);
            java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
            HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setRequestProperty("Accept", "application/json");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(30000);
            
            // 写入请求参数
            try (OutputStream os = conn.getOutputStream();
                 OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
                osw.write(params.toString());
                osw.flush();
            }
            
            // 读取响应
            int statusCode = conn.getResponseCode();
            BufferedReader reader;
            if (statusCode >= 200 && statusCode < 300) {
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            } else {
                reader = new BufferedReader(new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8));
            }
            
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            
            String responseStr = response.toString();
            log.info("获取访问令牌响应: statusCode={}, response={}", statusCode, responseStr);
            
            if (statusCode < 200 || statusCode >= 300) {
                throw new RuntimeException("获取访问令牌失败: HTTP " + statusCode + ", response=" + responseStr);
            }
            
            return JSON.parseObject(responseStr);
        } catch (Exception e) {
            log.error("获取访问令牌失败", e);
            throw new RuntimeException("获取访问令牌失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 刷新访问令牌
     * 
     * @param appId 应用ID
     * @param appSecret 应用密钥
     * @param refreshToken 刷新令牌
     * @param refreshTokenUrl 刷新令牌地址
     * @return 包含新的access_token和refresh_token的JSON对象
     */
    public static JSONObject refreshAccessToken(String appId, String appSecret, String refreshToken, String refreshTokenUrl) {
        try {
            // 构建请求参数
            StringBuilder params = new StringBuilder();
            params.append("grant_type=refresh_token");
            params.append("&client_id=").append(appId);
            params.append("&client_secret=").append(appSecret);
            params.append("&refresh_token=").append(refreshToken);
            
            // 直接使用HttpURLConnection，不使用代理，避免被nginx拦截
            URL url = new URL(refreshTokenUrl);
            java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
            HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            conn.setRequestProperty("Accept", "application/json");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(30000);
            
            // 写入请求参数
            try (OutputStream os = conn.getOutputStream();
                 OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
                osw.write(params.toString());
                osw.flush();
            }
            
            // 读取响应
            int statusCode = conn.getResponseCode();
            BufferedReader reader;
            if (statusCode >= 200 && statusCode < 300) {
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            } else {
                reader = new BufferedReader(new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8));
            }
            
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            
            String responseStr = response.toString();
            log.info("刷新访问令牌响应: statusCode={}, response={}", statusCode, responseStr);
            
            if (statusCode < 200 || statusCode >= 300) {
                throw new RuntimeException("刷新访问令牌失败: HTTP " + statusCode + ", response=" + responseStr);
            }
            
            return JSON.parseObject(responseStr);
        } catch (Exception e) {
            log.error("刷新访问令牌失败", e);
            throw new RuntimeException("刷新访问令牌失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 调用腾讯文档API
     * 
     * @param accessToken 访问令牌
     * @param apiUrl API地址
     * @param method 请求方法 GET/POST/PUT/DELETE
     * @param body 请求体（JSON格式）
     * @return API响应
     */
    public static JSONObject callApi(String accessToken, String apiUrl, String method, String body) {
        try {
            log.info("调用腾讯文档API: url={}, method={}", apiUrl, method);
            
            URL url = new URL(apiUrl);
            // 使用Proxy.NO_PROXY确保不使用系统代理，直接连接到腾讯文档API
            java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
            HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy);
            
            conn.setRequestMethod(method);
            conn.setRequestProperty("Authorization", "Bearer " + accessToken);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Accept", "application/json");
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setConnectTimeout(10000);
            conn.setReadTimeout(30000);
            
            // 写入请求体
            if (body != null && !body.isEmpty()) {
                try (OutputStream os = conn.getOutputStream();
                     OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
                    osw.write(body);
                    osw.flush();
                }
            }
            
            // 读取响应
            int statusCode = conn.getResponseCode();
            log.info("腾讯文档API响应状态码: {}", statusCode);
            
            BufferedReader reader;
            if (statusCode >= 200 && statusCode < 300) {
                reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            } else {
                reader = new BufferedReader(new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8));
            }
            
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            
            String responseStr = response.toString();
            log.info("腾讯文档API响应: statusCode={}, responseLength={}, responsePreview={}", 
                statusCode, responseStr.length(), 
                responseStr.length() > 200 ? responseStr.substring(0, 200) + "..." : responseStr);
            
            // 检查响应是否被代理拦截（返回HTML说明被拦截了）
            if (responseStr.trim().startsWith("<html") || responseStr.trim().startsWith("<!DOCTYPE")) {
                log.error("响应被代理拦截，返回了HTML页面而不是JSON。响应内容: {}", 
                    responseStr.length() > 500 ? responseStr.substring(0, 500) + "..." : responseStr);
                throw new RuntimeException("请求被代理拦截，返回了HTML页面。请检查系统代理设置或网络配置。响应: " + 
                    (responseStr.length() > 200 ? responseStr.substring(0, 200) : responseStr));
            }
            
            // 尝试解析JSON
            JSONObject result = JSON.parseObject(responseStr);
            
            // 检查错误码
            if (result.containsKey("error_code") && result.getIntValue("error_code") != 0) {
                String errorMsg = result.getString("error_msg");
                log.error("腾讯文档API调用失败: error_code={}, error_msg={}", 
                    result.getIntValue("error_code"), errorMsg);
                throw new RuntimeException("腾讯文档API调用失败: " + errorMsg);
            }
            
            if (statusCode < 200 || statusCode >= 300) {
                throw new RuntimeException("HTTP请求失败: statusCode=" + statusCode + ", response=" + responseStr);
            }
            
            return result;
        } catch (Exception e) {
            log.error("调用腾讯文档API失败: url={}, method={}", apiUrl, method, e);
            throw new RuntimeException("调用腾讯文档API失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 读取表格数据 - V3 API
     * 
     * @param accessToken 访问令牌
     * @param fileId 文件ID（在线表格的唯一标识）
     * @param sheetId 工作表ID（可从表格链接中获取，如 ?tab=BB08J2 中的 BB08J2）
     * @param range 范围，例如 "A1:Z100"（行列从0开始，遵循左闭右开原则）
     * @param apiBaseUrl API基础地址（默认：https://docs.qq.com/open/api/v3）
     * @return 表格数据（JSON格式，包含values数组）
     */
    public static JSONObject readSheetData(String accessToken, String fileId, String sheetId, String range, String apiBaseUrl) {
        // V3版本API路径格式：/open/api/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}/ranges/{range}
        String apiUrl = String.format("%s/spreadsheets/%s/sheets/%s/ranges/%s", apiBaseUrl, fileId, sheetId, range);
        log.info("读取表格数据 - fileId: {}, sheetId: {}, range: {}, apiUrl: {}", fileId, sheetId, range, apiUrl);
        return callApi(accessToken, apiUrl, "GET", null);
    }
    
    /**
     * 写入表格数据（V3 API）
     * 
     * @param accessToken 访问令牌
     * @param fileId 文件ID（在线表格的唯一标识）
     * @param sheetId 工作表ID（可从表格链接中获取，如 ?tab=BB08J2 中的 BB08J2）
     * @param range 范围，例如 "A1"（起始单元格位置）
     * @param values 要写入的数据，支持两种格式：
     *              1. 简单二维数组：[["值1", "值2"], ["值3", "值4"]]
     *              2. V3 API完整格式（包含CellData结构）
     * @param apiBaseUrl API基础地址（默认：https://docs.qq.com/open/api/v3）
     * @return 写入结果
     */
    public static JSONObject writeSheetData(String accessToken, String fileId, String sheetId, String range, Object values, String apiBaseUrl) {
        // V3版本API路径格式：/open/api/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}/ranges/{range}
        String apiUrl = String.format("%s/spreadsheets/%s/sheets/%s/ranges/%s", apiBaseUrl, fileId, sheetId, range);
        
        // 构建V3 API规范的请求体
        // 根据腾讯文档V3 API文档（https://docs.qq.com/open/document/app/openapi/v3/sheet/model/spreadsheet.html）
        // 对于简单的文本数据写入，可以直接使用values二维数组
        // 对于复杂的单元格数据（包含格式、类型等），需要使用完整的CellData结构
        JSONObject requestBody = new JSONObject();
        requestBody.put("values", values);
        
        log.info("写入表格数据 - fileId: {}, sheetId: {}, range: {}, apiUrl: {}", fileId, sheetId, range, apiUrl);
        log.debug("写入表格数据 - 请求体: {}", requestBody.toJSONString());
        
        return callApi(accessToken, apiUrl, "PUT", requestBody.toJSONString());
    }
    
    /**
     * 追加表格数据（在最后一行追加）- V3 API
     * 
     * @param accessToken 访问令牌
     * @param fileId 文件ID（在线表格的唯一标识）
     * @param sheetId 工作表ID（可从表格链接中获取，如 ?tab=BB08J2 中的 BB08J2）
     * @param values 要追加的数据，二维数组格式，例如：[["值1", "值2"], ["值3", "值4"]]
     * @param apiBaseUrl API基础地址（默认：https://docs.qq.com/open/api/v3）
     * @return 追加结果
     */
    public static JSONObject appendSheetData(String accessToken, String fileId, String sheetId, Object values, String apiBaseUrl) {
        try {
            // 先获取工作表信息，找到最后一行（V3版本路径）
            // V3版本API路径格式：/open/api/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}
            String infoUrl = String.format("%s/spreadsheets/%s/sheets/%s", apiBaseUrl, fileId, sheetId);
            log.info("获取工作表信息以追加数据 - apiUrl: {}", infoUrl);
            
            JSONObject sheetInfo = callApi(accessToken, infoUrl, "GET", null);
            
            // 获取行数（根据实际API响应调整）
            // V3 API可能返回的字段名：rowCount, row_count, properties.rowCount等
            // 根据腾讯文档V3 API文档，工作表信息返回格式：
            // { "properties": { "sheetId": "xxx", "rowCount": 100, "columnCount": 10, ... } }
            int rowCount = 0;
            if (sheetInfo.containsKey("properties")) {
                JSONObject properties = sheetInfo.getJSONObject("properties");
                if (properties != null && properties.containsKey("rowCount")) {
                    rowCount = properties.getIntValue("rowCount");
                }
            } else if (sheetInfo.containsKey("rowCount")) {
                rowCount = sheetInfo.getIntValue("rowCount");
            } else if (sheetInfo.containsKey("row_count")) {
                rowCount = sheetInfo.getIntValue("row_count");
            } else if (sheetInfo.containsKey("data")) {
                JSONObject data = sheetInfo.getJSONObject("data");
                if (data != null && data.containsKey("row_count")) {
                    rowCount = data.getIntValue("row_count");
                }
            }
            
            if (rowCount == 0) {
                log.warn("无法从API响应中获取行数，使用默认值1。响应数据: {}", sheetInfo);
                rowCount = 1; // 至少有一行（表头）
            }
            
            // 计算要写入的起始位置（在最后一行之后追加）
            String range = "A" + (rowCount + 1);
            
            log.info("追加数据到第 {} 行，range: {}", rowCount + 1, range);
            
            return writeSheetData(accessToken, fileId, sheetId, range, values, apiBaseUrl);
        } catch (Exception e) {
            log.error("追加表格数据失败 - fileId: {}, sheetId: {}", fileId, sheetId, e);
            throw new RuntimeException("追加表格数据失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取文件信息 - V3 API
     * 
     * @param accessToken 访问令牌
     * @param fileId 文件ID（在线表格的唯一标识）
     * @param apiBaseUrl API基础地址（默认：https://docs.qq.com/open/api/v3）
     * @return 文件信息（JSON格式，包含metadata、sheets等信息）
     *         返回格式示例：{ "fileId": "xxx", "metadata": {...}, "sheets": [...] }
     */
    public static JSONObject getFileInfo(String accessToken, String fileId, String apiBaseUrl) {
        // V3版本API路径格式：/open/api/v3/spreadsheets/{spreadsheetId}
        String apiUrl = String.format("%s/spreadsheets/%s", apiBaseUrl, fileId);
        log.info("获取文件信息 - fileId: {}, apiUrl: {}", fileId, apiUrl);
        return callApi(accessToken, apiUrl, "GET", null);
    }
    
    /**
     * 获取工作表列表 - V3 API
     * 
     * @param accessToken 访问令牌
     * @param fileId 文件ID（在线表格的唯一标识）
     * @param apiBaseUrl API基础地址（默认：https://docs.qq.com/open/api/v3）
     * @return 工作表列表（JSON格式，包含所有sheet的properties信息）
     *         返回格式示例：{ "sheets": [{ "properties": { "sheetId": "xxx", "title": "工作表1", ... } }] }
     */
    public static JSONObject getSheetList(String accessToken, String fileId, String apiBaseUrl) {
        // V3版本API路径格式：/open/api/v3/spreadsheets/{spreadsheetId}/sheets
        String apiUrl = String.format("%s/spreadsheets/%s/sheets", apiBaseUrl, fileId);
        log.info("获取工作表列表 - fileId: {}, apiUrl: {}", fileId, apiUrl);
        return callApi(accessToken, apiUrl, "GET", null);
    }
    
    /**
     * 获取用户信息
     * 
     * @param accessToken 访问令牌
     * @return 用户信息
     */
    public static JSONObject getUserInfo(String accessToken) {
        // 腾讯文档用户信息接口：https://docs.qq.com/open/document/app/oauth2/userinfo.html
        String apiUrl = "https://docs.qq.com/oauth/v2/userinfo";
        return callApi(accessToken, apiUrl, "GET", null);
    }
}

