package com.haobang.firewall;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;
import java.net.ProtocolException;

/**
 * 防火墙API客户端
 * 支持安恒信息-明御安全网关的黑名单/白名单操作
 */
@Component
public class FirewallApiClient {

    private static final Logger logger = LoggerFactory.getLogger(FirewallApiClient.class);

    private final ObjectMapper objectMapper = new ObjectMapper();

    // 黑名单API配置
    @Value("${blacklist.api.url:https://103.43.84.11/api/v3/Objects/Blacklist}")
    private String blacklistApiUrl;

    @Value("${blacklist.api.username:apt-admin103}")
    private String blacklistUsername;

    @Value("${blacklist.api.password:C9W2xYgfc%SN1}")
    private String blacklistPassword;

    // 白名单API配置
    @Value("${whitelist.api.url:https://103.43.84.11/api/v3/Policies/GlobalWhitelist}")
    private String whitelistApiUrl;

    @Value("${firewall.enabled:true}")
    private boolean firewallEnabled;

    /**
     * 添加IP到黑名单
     * @param ip IP地址
     * @param age 生命周期（秒），-1表示永久
     * @param reason 原因/备注
     * @return 操作结果
     */
    public FirewallResponse addToBlacklist(String ip, int age, String reason) {
        if (!firewallEnabled) {
            logger.info("[测试模式] 添加黑名单: ip={}, age={}, reason={}", ip, age, reason);
            return new FirewallResponse(true, "1", "测试模式-模拟成功");
        }

        Map<String, Object> payload = new HashMap<>();
        payload.put("blist", ip);
        payload.put("age", String.valueOf(age));
        payload.put("enable", "1");
        if (reason != null && !reason.isEmpty()) {
            payload.put("reason", reason);
        }

        return doPost(blacklistApiUrl, blacklistUsername, blacklistPassword, payload);
    }

    /**
     * 批量添加IP到黑名单
     * @param ips IP列表，每个元素包含 ip, age, reason
     * @return 操作结果
     */
    public FirewallResponse batchAddToBlacklist(List<Map<String, String>> ips) {
        if (!firewallEnabled) {
            logger.info("[测试模式] 批量添加黑名单: {}", ips);
            return new FirewallResponse(true, "1", "测试模式-模拟成功");
        }

        List<Map<String, String>> entries = new ArrayList<>();
        for (Map<String, String> ipInfo : ips) {
            Map<String, String> entry = new HashMap<>();
            entry.put("blist", ipInfo.get("ip"));
            entry.put("age", ipInfo.getOrDefault("age", "-1"));
            entry.put("enable", "1");
            if (ipInfo.containsKey("reason")) {
                entry.put("reason", ipInfo.get("reason"));
            }
            entries.add(entry);
        }

        Map<String, Object> payload = new HashMap<>();
        payload.put("blist_entry", entries);

        return doPost(blacklistApiUrl, blacklistUsername, blacklistPassword, payload);
    }

    /**
     * 从黑名单删除IP
     * @param ip IP地址
     * @return 操作结果
     */
    public FirewallResponse removeFromBlacklist(String ip) {
        if (!firewallEnabled) {
            logger.info("[测试模式] 删除黑名单: ip={}", ip);
            return new FirewallResponse(true, "1", "测试模式-模拟成功");
        }

        String deleteUrl = blacklistApiUrl + "/blist/" + ip;
        return doDelete(deleteUrl, blacklistUsername, blacklistPassword);
    }

    /**
     * 批量从黑名单删除IP
     * @param ips IP地址列表
     * @return 操作结果
     */
    public FirewallResponse batchRemoveFromBlacklist(List<String> ips) {
        if (!firewallEnabled) {
            logger.info("[测试模式] 批量删除黑名单: {}", ips);
            return new FirewallResponse(true, "1", "测试模式-模拟成功");
        }

        List<Map<String, String>> entries = ips.stream()
                .map(ip -> {
                    Map<String, String> entry = new HashMap<>();
                    entry.put("blist", ip);
                    return entry;
                })
                .collect(Collectors.toList());

        Map<String, Object> payload = new HashMap<>();
        payload.put("blist_entry", entries);

        return doDelete(blacklistApiUrl, blacklistUsername, blacklistPassword, payload);
    }

    /**
     * 添加IP到白名单
     * @param ip IP地址
     * @param name 名称
     * @param desc 描述
     * @return 操作结果
     */
    public FirewallResponse addToWhitelist(String ip, String name, String desc) {
        if (!firewallEnabled) {
            logger.info("[测试模式] 添加白名单: ip={}, name={}", ip, name);
            return new FirewallResponse(true, "1", "测试模式-模拟成功");
        }

        List<Map<String, String>> addresses = new ArrayList<>();
        Map<String, String> address = new HashMap<>();
        address.put("address", ip);
        addresses.add(address);

        Map<String, Object> payload = new HashMap<>();
        payload.put("enable", "1");
        payload.put("name", name);
        payload.put("desc", desc != null ? desc : "");
        payload.put("addr", addresses);

        return doPost(whitelistApiUrl, blacklistUsername, blacklistPassword, payload);
    }

    /**
     * 删除白名单
     * @param name 白名单名称
     * @return 操作结果
     */
    public FirewallResponse removeFromWhitelist(String name) {
        if (!firewallEnabled) {
            logger.info("[测试模式] 删除白名单: name={}", name);
            return new FirewallResponse(true, "1", "测试模式-模拟成功");
        }

        String deleteUrl = whitelistApiUrl + "/name/" + name;
        return doDelete(deleteUrl, blacklistUsername, blacklistPassword);
    }

    /**
     * 批量删除白名单
     * @param names 白名单名称列表
     * @return 操作结果
     */
    public FirewallResponse batchRemoveFromWhitelist(List<String> names) {
        if (!firewallEnabled) {
            logger.info("[测试模式] 批量删除白名单: {}", names);
            return new FirewallResponse(true, "1", "测试模式-模拟成功");
        }

        List<Map<String, String>> nameList = names.stream()
                .map(name -> {
                    Map<String, String> entry = new HashMap<>();
                    entry.put("name", name);
                    return entry;
                })
                .collect(Collectors.toList());

        Map<String, Object> payload = new HashMap<>();
        payload.put("name_list", nameList);

        String batchDeleteUrl = whitelistApiUrl + "Batch";
        return doDelete(batchDeleteUrl, blacklistUsername, blacklistPassword, payload);
    }

    /**
     * 执行POST请求
     */
    private FirewallResponse doPost(String urlStr, String username, String password, Map<String, Object> payload) {
        HttpURLConnection conn = null;
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            setupConnection(conn, username, password, "POST");

            // 发送请求体
            ObjectMapper mapper = new ObjectMapper();
            String jsonBody = mapper.writeValueAsString(payload);
            
            try (OutputStream os = conn.getOutputStream()) {
                os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
            }

            // 获取响应
            int responseCode = conn.getResponseCode();
            String response = readResponse(conn);
            
            logger.info("POST请求响应: url={}, code={}, response={}", urlStr, responseCode, response);

            // 解析响应
            JsonNode jsonNode = mapper.readTree(response);
            int code = jsonNode.has("code") ? jsonNode.get("code").asInt() : responseCode;
            String msg = jsonNode.has("msg") && !jsonNode.get("msg").isNull() ? jsonNode.get("msg").asText() : "";

            return new FirewallResponse(code == 1, String.valueOf(code), msg, response);

        } catch (Exception e) {
            logger.error("POST请求失败: url={}, error={}", urlStr, e.getMessage(), e);
            return new FirewallResponse(false, "-1", "请求失败: " + e.getMessage());
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }

    /**
     * 执行DELETE请求（无请求体）
     */
    private FirewallResponse doDelete(String urlStr, String username, String password) {
        HttpURLConnection conn = null;
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            setupConnection(conn, username, password, "DELETE");

            int responseCode = conn.getResponseCode();
            String response = readResponse(conn);
            
            logger.info("DELETE请求响应: url={}, code={}, response={}", urlStr, responseCode, response);

            ObjectMapper mapper = new ObjectMapper();
            JsonNode jsonNode = mapper.readTree(response);
            int code = jsonNode.has("code") ? jsonNode.get("code").asInt() : responseCode;
            String msg = jsonNode.has("msg") && !jsonNode.get("msg").isNull() ? jsonNode.get("msg").asText() : "";

            return new FirewallResponse(code == 1, String.valueOf(code), msg, response);

        } catch (Exception e) {
            logger.error("DELETE请求失败: url={}, error={}", urlStr, e.getMessage(), e);
            return new FirewallResponse(false, "-1", "请求失败: " + e.getMessage());
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }

    /**
     * 执行DELETE请求（带请求体）
     */
    private FirewallResponse doDelete(String urlStr, String username, String password, Map<String, Object> payload) {
        HttpURLConnection conn = null;
        try {
            URL url = new URL(urlStr);
            conn = (HttpURLConnection) url.openConnection();
            setupConnection(conn, username, password, "DELETE");

            // 发送请求体
            ObjectMapper mapper = new ObjectMapper();
            String jsonBody = mapper.writeValueAsString(payload);
            
            try (OutputStream os = conn.getOutputStream()) {
                os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
            }

            int responseCode = conn.getResponseCode();
            String response = readResponse(conn);
            
            logger.info("DELETE请求响应: url={}, code={}, response={}", urlStr, responseCode, response);

            JsonNode jsonNode = mapper.readTree(response);
            int code = jsonNode.has("code") ? jsonNode.get("code").asInt() : responseCode;
            String msg = jsonNode.has("msg") && !jsonNode.get("msg").isNull() ? jsonNode.get("msg").asText() : "";

            return new FirewallResponse(code == 1, String.valueOf(code), msg, response);

        } catch (Exception e) {
            logger.error("DELETE请求失败: url={}, error={}", urlStr, e.getMessage(), e);
            return new FirewallResponse(false, "-1", "请求失败: " + e.getMessage());
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }

    /**
     * 配置HTTP连接
     */
    private void setupConnection(HttpURLConnection conn, String username, String password, String method)
            throws NoSuchAlgorithmException, KeyManagementException, ProtocolException{
        conn.setRequestMethod(method);
        conn.setConnectTimeout(10000);
        conn.setReadTimeout(30000);
        conn.setDoInput(true);
        conn.setDoOutput(true);
        
        // 设置请求头
        conn.setRequestProperty("Content-Type", "application/json");
        conn.setRequestProperty("Accept", "application/json");
        
        // HTTP Basic Auth
        String auth = username + ":" + password;
        String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
        conn.setRequestProperty("Authorization", "Basic " + encodedAuth);
        
        // 信任所有证书（用于HTTPS）
        if (conn instanceof HttpsURLConnection) {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
                public void checkClientTrusted(X509Certificate[] certs, String authType) {}
                public void checkServerTrusted(X509Certificate[] certs, String authType) {}
            }}, new java.security.SecureRandom());
            
            ((HttpsURLConnection) conn).setSSLSocketFactory(sslContext.getSocketFactory());
            ((HttpsURLConnection) conn).setHostnameVerifier((hostname, session) -> true);
        }
    }

    /**
     * 读取响应内容
     */
    private String readResponse(HttpURLConnection conn) throws IOException {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                        conn.getResponseCode() >= 400 ? conn.getErrorStream() : conn.getInputStream(),
                        StandardCharsets.UTF_8))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        }
    }

    /**
     * 防火墙响应结果类
     */
    public static class FirewallResponse {
        private boolean success;
        private String code;
        private String message;
        private String rawResponse;

        public FirewallResponse(boolean success, String code, String message) {
            this.success = success;
            this.code = code;
            this.message = message;
        }

        public FirewallResponse(boolean success, String code, String message, String rawResponse) {
            this.success = success;
            this.code = code;
            this.message = message;
            this.rawResponse = rawResponse;
        }

        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        public String getCode() { return code; }
        public void setCode(String code) { this.code = code; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        public String getRawResponse() { return rawResponse; }
        public void setRawResponse(String rawResponse) { this.rawResponse = rawResponse; }

        @Override
        public String toString() {
            return "FirewallResponse{" +
                    "success=" + success +
                    ", code='" + code + '\'' +
                    ", message='" + message + '\'' +
                    '}';
        }
    }
}
