package com.nbport.zgwl.test;

import com.nbport.zgwl.seal.utils.SealHttpClient;
import com.nbport.zgwl.seal.utils.HMacSHA256Util;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.http.MediaType;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.cert.X509Certificate;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

public class SealDownloadManualTest {

    private static final String BASE_URL = "https://saasapi.certca.cn";
    private static final String APP_KEY = "A7C4FD32BE454B5";
    private static final String APP_SECRET = "6c74358c28c149f18242bd614a101910";
    private static final String SAVE_DIR = "D:/temp-seal-download";

    public static void main(String[] args) throws Exception {
        String contractId = args.length > 0 ? args[0] : "63b5552bfebe44a9de0d16d39162b678";
        System.out.println("===== Seal Download Test =====");

        String token = getAccessToken();
        System.out.println("[1] token OK");

        JSONObject body = new JSONObject();
        body.put("contractId", contractId);
        String response = SealHttpClient.post(
                BASE_URL + "/saas/api/contract/download",
                body.toJSONString(), token, MediaType.APPLICATION_JSON_VALUE);
        JSONObject result = JSON.parseObject(response);
        if (result == null || !result.getBooleanValue("isSuccess")) {
            System.err.println("[FAIL] " + response);
            return;
        }
        Object dataObj = result.get("data");
        String rawUrl = null;
        if (dataObj instanceof JSONObject) {
            rawUrl = ((JSONObject) dataObj).getString("downloadUrl");
        } else if (dataObj instanceof String) {
            rawUrl = (String) dataObj;
        }
        System.out.println("[2] rawUrl: " + rawUrl);

        // 尝试多种方式下载
        System.out.println("\n[3] Trying download methods...");

        // 方法1: 直接GET
        System.out.println("  [3a] Direct GET...");
        tryDownload(rawUrl, null, false);

        // 方法2: 带 access_token header
        System.out.println("  [3b] GET + access_token header...");
        tryDownload(rawUrl, token, false);

        // 方法3: URL编码中文参数后再GET
        String encodedUrl = encodeChineseInUrl(rawUrl);
        if (!encodedUrl.equals(rawUrl)) {
            System.out.println("  [3c] GET with URL-encoded params...");
            tryDownload(encodedUrl, null, false);
            System.out.println("  [3d] GET URL-encoded + access_token...");
            tryDownload(encodedUrl, token, false);
        }

        // 方法4: POST方式
        System.out.println("  [3e] POST download (as API)...");
        tryPostDownload(rawUrl, token);

        // 方法5: 去掉query string
        String noQuery = rawUrl.contains("?") ? rawUrl.substring(0, rawUrl.indexOf('?')) : rawUrl;
        System.out.println("  [3f] GET without query string...");
        tryDownload(noQuery, token, false);

        System.out.println("\n===== Done =====");
    }

    private static String encodeChineseInUrl(String urlStr) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < urlStr.length(); i++) {
            char c = urlStr.charAt(i);
            if (c > 127) {
                sb.append(URLEncoder.encode(String.valueOf(c), StandardCharsets.UTF_8));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    private static void tryDownload(String fileUrl, String token, boolean isPost) {
        try {
            URL url = new URL(fileUrl);
            HttpURLConnection conn = openConnection(url);
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(30000);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
            if (token != null && !token.isBlank()) {
                conn.setRequestProperty("access_token", token);
            }
            if (isPost) {
                conn.setRequestMethod("POST");
                conn.setDoOutput(true);
                conn.setRequestProperty("Content-Type", "application/json");
                try (OutputStream os = conn.getOutputStream()) {
                    os.write("{}".getBytes(StandardCharsets.UTF_8));
                }
            }

            int code = conn.getResponseCode();
            if (code >= 200 && code < 300) {
                long size = conn.getContentLengthLong();
                System.out.println("      [OK] HTTP " + code + ", size=" + size);
            } else {
                String err = readStream(conn.getErrorStream());
                System.out.println("      [FAIL] HTTP " + code + " body=" + err);
            }
            conn.disconnect();
        } catch (Exception e) {
            System.out.println("      [ERR] " + e.getMessage());
        }
    }

    private static void tryPostDownload(String fileUrl, String token) {
        try {
            URL url = new URL(fileUrl);
            HttpURLConnection conn = openConnection(url);
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);
            conn.setConnectTimeout(15000);
            conn.setReadTimeout(30000);
            conn.setRequestProperty("User-Agent", "Mozilla/5.0");
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            if (token != null && !token.isBlank()) {
                conn.setRequestProperty("access_token", token);
            }
            try (OutputStream os = conn.getOutputStream()) {
                os.write(new byte[0]);
            }
            int code = conn.getResponseCode();
            if (code >= 200 && code < 300) {
                System.out.println("      [OK] HTTP " + code);
            } else {
                String err = readStream(conn.getErrorStream());
                System.out.println("      [FAIL] HTTP " + code + " body=" + err);
            }
            conn.disconnect();
        } catch (Exception e) {
            System.out.println("      [ERR] " + e.getMessage());
        }
    }

    private static String getAccessToken() throws Exception {
        long ts = System.currentTimeMillis();
        JSONObject signData = new JSONObject();
        signData.put("appKey", APP_KEY);
        signData.put("timestamp", ts);
        String sig = HMacSHA256Util.encrypt(JSON.toJSONString(signData), APP_SECRET);
        JSONObject req = new JSONObject();
        req.put("appKey", APP_KEY);
        req.put("timestamp", ts);
        req.put("signature", sig);
        String resp = SealHttpClient.post(
                BASE_URL + "/saas/api/token/getAccessToken",
                req.toJSONString(), null, MediaType.APPLICATION_JSON_VALUE);
        return JSON.parseObject(resp).getJSONObject("data").getString("access_token");
    }

    private static HttpURLConnection openConnection(URL url) throws Exception {
        if ("https".equalsIgnoreCase(url.getProtocol())) {
            HttpsURLConnection h = (HttpsURLConnection) url.openConnection();
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[]{new X509TrustManager() {
                public void checkClientTrusted(X509Certificate[] c, String a) {}
                public void checkServerTrusted(X509Certificate[] c, String a) {}
                public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
            }}, new java.security.SecureRandom());
            h.setSSLSocketFactory(ctx.getSocketFactory());
            h.setHostnameVerifier((host, sess) -> true);
            return h;
        }
        return (HttpURLConnection) url.openConnection();
    }

    private static String readStream(InputStream is) throws IOException {
        if (is == null) return "";
        StringBuilder sb = new StringBuilder();
        try (BufferedReader r = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
            String line; while ((line = r.readLine()) != null) sb.append(line);
        }
        return sb.toString();
    }
}