package com.haobang.interlocking;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.haobang.firewall.FirewallApiClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 探针联动封禁服务
 * 核心业务逻辑：
 * 1. 从syslog-consumer获取待执行的封禁指令
 * 2. 解析封禁指令，生成逐条指令
 * 3. 调用防火墙API执行封禁
 * 4. 记录封禁结果到syslog-consumer
 * 5. 更新指令状态
 */
@Service
public class InterlockingService {

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

    @Autowired
    private InterlockingApiClient apiClient;

    @Autowired
    private FirewallApiClient firewallClient;

    private final ObjectMapper objectMapper = new ObjectMapper();

    // 探针ID，从配置读取
    @Value("${app.service.device_collect_id:1}")
    private Integer probeId;

    // 是否启用联动功能
    @Value("${interlocking.enabled:true}")
    private boolean interlockingEnabled;

    // 执行锁，防止重复执行
    private final AtomicBoolean executing = new AtomicBoolean(false);

    @PostConstruct
    public void init() {
        logger.info("探针联动封禁服务初始化完成，探针ID: {}, 启用状态: {}", probeId, interlockingEnabled);
    }

    /**
     * 定时任务：检查并执行待处理的封禁指令
     * 每60秒执行一次
     */
    @Scheduled(fixedDelay = 60000)
    public void processPendingCommands() {
        if (!interlockingEnabled) {
            return;
        }

        // 防止重复执行
        if (!executing.compareAndSet(false, true)) {
            logger.debug("上次执行尚未完成，跳过本次调度");
            return;
        }

        try {
            logger.info("开始检查待执行的封禁指令...");

            // 1. 获取待执行的封禁指令
            List<Map<String, Object>> pendingCommands = apiClient.getPendingCommands(probeId.longValue());

            if (pendingCommands.isEmpty()) {
                logger.debug("没有待执行的封禁指令");
                return;
            }

            logger.info("获取到 {} 条待执行的封禁指令", pendingCommands.size());

            // 2. 逐条处理指令
            for (Map<String, Object> cmd : pendingCommands) {
                try {
                    processCommand(cmd);
                } catch (Exception e) {
                    logger.error("处理封禁指令异常: cmdId={}, error={}", cmd.get("id"), e.getMessage(), e);
                }
            }

        } catch (Exception e) {
            logger.error("检查待执行指令失败: {}", e.getMessage(), e);
        } finally {
            executing.set(false);
        }
    }

    /**
     * 处理单条封禁指令
     * 指令数据结构（JSON字段名为驼峰格式）：
     * - banIps: 封禁IP数组
     * - banType: 封禁类型（0:黑名单、1:白名单）
     * - banOperationType: 操作类型（0:新增、1:删除）
     * - banDuration: 封禁时长（秒）
     * - deviceInterlockingIp: 联动设备IP数组
     * - deviceInterlockingId: 联动设备ID数组
     */
    private void processCommand(Map<String, Object> cmd) {
        Long cmdId = ((Number) cmd.get("id")).longValue();
        // JSON字段名使用驼峰格式
        List<String> banIps = parseStringArray(cmd.get("banIps"));
        String banType = (String) cmd.get("banType");
        Integer banOperationType = cmd.get("banOperationType") != null ?
                ((Number) cmd.get("banOperationType")).intValue() : 0;
        Integer banDuration = cmd.get("banDuration") != null ?
                ((Number) cmd.get("banDuration")).intValue() : -1;
        List<String> deviceIps = parseStringArray(cmd.get("deviceInterlockingIp"));

        logger.info("开始处理封禁指令: cmdId={}, banType={}, operationType={}, ipCount={}",
                cmdId, banType, banOperationType, banIps.size());

        try {
            // 3. 更新状态为执行中
            if (!apiClient.updateStatusToExecuting(cmdId)) {
                logger.warn("更新指令状态为执行中失败，跳过此指令: cmdId={}", cmdId);
                return;
            }

            if (banIps.isEmpty()) {
                logger.warn("封禁IP列表为空: cmdId={}", cmdId);
                apiClient.updateStatusToCompleted(cmdId);
                return;
            }

            // 4. 根据设备列表执行封禁
            int successCount = 0;
            int failCount = 0;
            List<Map<String, Object>> allResults = new ArrayList<>();

            // 遍历每个联动设备执行封禁
            for (String deviceIp : deviceIps) {
                // 设置防火墙客户端的设备IP（这里简化处理，实际可能需要从配置获取）
                List<Map<String, Object>> results = executeBlockOperations(
                        deviceIp, banType, banOperationType, banIps, banDuration, cmdId);
                allResults.addAll(results);

                for (Map<String, Object> result : results) {
                    // banResult: 1表示成功，0表示失败
                    if ("1".equals(result.get("banResult"))) {
                        successCount++;
                    } else {
                        failCount++;
                    }
                }
            }

            // 5. 批量记录封禁结果
            for (Map<String, Object> result : allResults) {
                result.put("deviceInterlockingCmdId", cmdId);
                result.put("probeId", probeId);
                result.put("banMethod", "1"); // 自动化封禁
            }

            boolean logSaved = apiClient.batchInsertLogs(allResults);
            if (!logSaved) {
                logger.warn("批量记录封禁结果失败: cmdId={}", cmdId);
            }

            // 6. 更新指令状态为执行完成
            if (apiClient.updateStatusToCompleted(cmdId)) {
                logger.info("封禁指令执行完成: cmdId={}, 成功={}, 失败={}", cmdId, successCount, failCount);
            } else {
                logger.error("更新指令状态为执行完成失败: cmdId={}", cmdId);
            }

        } catch (Exception e) {
            logger.error("处理封禁指令异常: cmdId={}, error={}", cmdId, e.getMessage(), e);
            apiClient.updateStatusToFailed(cmdId, e.getMessage());
        }
    }

    /**
     * 解析PostgreSQL数组格式
     */
    private List<String> parseStringArray(Object obj) {
        List<String> result = new ArrayList<>();
        if (obj == null) {
            return result;
        }

        try {
            if (obj instanceof List) {
                for (Object item : (List<?>) obj) {
                    result.add(String.valueOf(item));
                }
            } else if (obj instanceof String) {
                String str = (String) obj;
                // 处理PostgreSQL数组格式 {a,b,c}
                if (str.startsWith("{") && str.endsWith("}")) {
                    str = str.substring(1, str.length() - 1);
                    for (String item : str.split(",")) {
                        if (!item.isEmpty()) {
                            result.add(item.trim());
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("解析数组失败: {}", e.getMessage());
        }

        return result;
    }

    /**
     * 执行封禁操作
     * @param deviceIp 设备IP
     * @param banType 封禁类型（0:黑名单、1:白名单）
     * @param operationType 操作类型（0:新增、1:删除）
     * @param ipList IP列表
     * @param duration 封禁时长
     * @param cmdId 指令ID
     */
    private List<Map<String, Object>> executeBlockOperations(
            String deviceIp, String banType, int operationType,
            List<String> ipList, int duration, Long cmdId) {

        List<Map<String, Object>> results = new ArrayList<>();

        // 确定操作类型
        String operationName;
        if ("0".equals(banType)) {
            // 黑名单
            operationName = operationType == 0 ? "add_blacklist" : "del_blacklist";
        } else {
            // 白名单
            operationName = operationType == 0 ? "add_whitelist" : "del_whitelist";
        }

        for (String ip : ipList) {
            Map<String, Object> result = new HashMap<>();
            result.put("banIp", ip);
            result.put("deviceInterlockingId", null); // 后续可关联
            result.put("deviceName", deviceIp);
            result.put("banResult", "0"); // 默认失败，0表示失败
            result.put("reqBody", "");
            result.put("respBody", "");

            try {
                FirewallApiClient.FirewallResponse response;

                switch (operationName) {
                    case "add_blacklist":
                        response = firewallClient.addToBlacklist(ip, duration, "联动封禁");
                        break;
                    case "del_blacklist":
                        response = firewallClient.removeFromBlacklist(ip);
                        break;
                    case "add_whitelist":
                        response = firewallClient.addToWhitelist(ip, "whitelist_" + ip, "联动封禁白名单");
                        break;
                    case "del_whitelist":
                        response = firewallClient.removeFromWhitelist(ip);
                        break;
                    default:
                        logger.warn("未知的指令类型: {}", operationName);
                        result.put("respBody", "未知的指令类型: " + operationName);
                        results.add(result);
                        continue;
                }

                // banResult: 1表示成功，0表示失败
                result.put("banResult", response.isSuccess() ? "1" : "0");
                result.put("respBody", response.getRawResponse());

                // 构建请求body用于记录
                result.put("reqBody", buildRequestBody(operationName, ip, duration));

            } catch (Exception e) {
                logger.error("执行封禁操作异常: ip={}, operation={}, error={}", ip, operationName, e.getMessage());
                result.put("respBody", "执行异常: " + e.getMessage());
            }

            results.add(result);
        }

        return results;
    }

    /**
     * 构建请求body用于记录
     */
    private String buildRequestBody(String cmdType, String ip, int duration) {
        try {
            Map<String, Object> body = new HashMap<>();
            switch (cmdType) {
                case "add_blacklist":
                    body.put("blist", ip);
                    body.put("age", String.valueOf(duration));
                    body.put("enable", "1");
                    break;
                case "del_blacklist":
                    body.put("blist", ip);
                    break;
                case "add_whitelist":
                    body.put("enable", "1");
                    body.put("name", "whitelist_" + ip);
                    List<Map<String, String>> addr = new ArrayList<>();
                    Map<String, String> addrItem = new HashMap<>();
                    addrItem.put("address", ip);
                    addr.add(addrItem);
                    body.put("addr", addr);
                    break;
                case "del_whitelist":
                    body.put("name", ip);
                    break;
            }
            return objectMapper.writeValueAsString(body);
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * 手动触发封禁
     */
    public Map<String, Object> manualBlock(String ip, String cmdType, int age, String reason) {
        Map<String, Object> result = new HashMap<>();

        try {
            FirewallApiClient.FirewallResponse response;

            switch (cmdType) {
                case "add_blacklist":
                    response = firewallClient.addToBlacklist(ip, age, reason);
                    break;
                case "del_blacklist":
                    response = firewallClient.removeFromBlacklist(ip);
                    break;
                case "add_whitelist":
                    response = firewallClient.addToWhitelist(ip, "manual_" + ip, reason);
                    break;
                case "del_whitelist":
                    response = firewallClient.removeFromWhitelist(ip);
                    break;
                default:
                    result.put("success", false);
                    result.put("message", "未知的指令类型: " + cmdType);
                    return result;
            }

            result.put("success", response.isSuccess());
            result.put("code", response.getCode());
            result.put("message", response.getMessage());

        } catch (Exception e) {
            logger.error("手动封禁异常: ip={}, cmdType={}, error={}", ip, cmdType, e.getMessage());
            result.put("success", false);
            result.put("message", "执行异常: " + e.getMessage());
        }

        return result;
    }

    /**
     * 批量手动封禁
     */
    public Map<String, Object> batchManualBlock(List<String> ips, String cmdType, int age, String reason) {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, String>> ipList = new ArrayList<>();

        for (String ip : ips) {
            Map<String, String> ipInfo = new HashMap<>();
            ipInfo.put("ip", ip);
            ipInfo.put("age", String.valueOf(age));
            ipInfo.put("reason", reason);
            ipList.add(ipInfo);
        }

        try {
            FirewallApiClient.FirewallResponse response;

            if ("add_blacklist".equals(cmdType)) {
                response = firewallClient.batchAddToBlacklist(ipList);
            } else if ("del_blacklist".equals(cmdType)) {
                response = firewallClient.batchRemoveFromBlacklist(ips);
            } else {
                result.put("success", false);
                result.put("message", "批量操作暂不支持此类型: " + cmdType);
                return result;
            }

            result.put("success", response.isSuccess());
            result.put("code", response.getCode());
            result.put("message", response.getMessage());

        } catch (Exception e) {
            logger.error("批量手动封禁异常: cmdType={}, error={}", cmdType, e.getMessage());
            result.put("success", false);
            result.put("message", "执行异常: " + e.getMessage());
        }

        return result;
    }

    public Integer getProbeId() { return probeId; }
    public void setProbeId(Integer probeId) { this.probeId = probeId; }
    public boolean isInterlockingEnabled() { return interlockingEnabled; }
    public void setInterlockingEnabled(boolean interlockingEnabled) { this.interlockingEnabled = interlockingEnabled; }
}
