package com.Modules.NormalData;

import cn.hutool.core.date.DateTime;
import com.common.entity.DeviceCollectTask;
import com.common.entity.DeviceDevice;
import com.common.entity.RuleContent.*;
import com.common.entity.SyslogNonNormalMessage;
import com.common.mapper.DmColumnMapper;
import com.common.mapper.DmNormalizeRuleMapper;
import com.common.service.*;
import com.common.util.*;
import com.config.AppProperties;
import com.config.KafkaConsumerProperties;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.joda.time.LocalDateTime;
import org.json.JSONObject;
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.stereotype.Service;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
import com.common.entity.SyslogMessage;

/**
 * 日志标准化处理器
 * 线程安全版本：运行时状态封装为 ProcessContext，每次 process() 调用独立（解决多线程 NPE 问题）
 */
@Service
public class LogNormalProcessor {
    private static final Logger logger = LoggerFactory.getLogger(LogNormalProcessor.class);

    // ==================== 依赖注入（Spring Bean，单例，线程安全）====================
    private final DmNormalizeRuleService dmNormalizeRuleService;
    private final DmColumnService dmColumnService;
    private final SyslogNormalDataService syslogNormalDataService;
    private final SyslogNonNormalMessageService messageService;
    private final LogDataFilterService logDataFilterService;
    private final LogDataCompleteService logDataCompleteService;
    private final DeviceCollectTaskService deviceCollectTaskService;
    private final DeviceDeviceService deviceDeviceService;
    private final DmColumnMapper dmColumnMapper;
    private final DmNormalizeRuleMapper dmNormalizeRuleMapper;
    private final KafkaConsumerProperties kafkaConsumerProperties;
    private final AppProperties appProperties;

    /**
     * 请求级处理上下文 —— 每个 process() 调用创建新实例，彻底解决多线程竞态条件
     */
    private static class ProcessContext {
        String strLogMsg;
        String strKafkaMessage;
        String strDeviceInfo;
        String strDataType = "json";
        Map<String, Object> messageMap;
        Map<String, String> deviceInfoMap;
        String strSyslogUUID;
        String strSyslogTopic;
        boolean isSaveNonNormal = false;
        SyslogNonNormalMessage syslogNonNormalMessage = new SyslogNonNormalMessage();
        List<Map<String, Object>> dmNormalizeRuleList;
        List<Map<String, Object>> dmColumnList;
        LinkedHashMap<String, Object> OrginalColumnMap;
    }

    // ==================== 构造器注入（Spring 自动完成）====================
    @Autowired
    public LogNormalProcessor(
            DmNormalizeRuleService dmNormalizeRuleService,
            DmColumnService dmColumnService,
            SyslogNormalDataService syslogNormalDataService,
            SyslogNonNormalMessageService messageService,
            LogDataFilterService logDataFilterService,
            LogDataCompleteService logDataCompleteService,
            DeviceCollectTaskService deviceCollectTaskService,
            DeviceDeviceService deviceDeviceService,
            DmColumnMapper dmColumnMapper,
            DmNormalizeRuleMapper dmNormalizeRuleMapper,
            KafkaConsumerProperties kafkaConsumerProperties,
            AppProperties appProperties
    ) {
        this.dmNormalizeRuleService = dmNormalizeRuleService;
        this.dmColumnService = dmColumnService;
        this.syslogNormalDataService = syslogNormalDataService;
        this.messageService = messageService;
        this.logDataFilterService = logDataFilterService;
        this.logDataCompleteService = logDataCompleteService;
        this.deviceCollectTaskService = deviceCollectTaskService;
        this.deviceDeviceService = deviceDeviceService;
        this.dmColumnMapper = dmColumnMapper;
        this.dmNormalizeRuleMapper = dmNormalizeRuleMapper;
        this.kafkaConsumerProperties = kafkaConsumerProperties;
        this.appProperties = appProperties;
    }

    /**
     * 处理一条日志消息（线程安全：每次调用创建独立的 ProcessContext）
     *
     * @param logMsg     完整日志消息（含头部）
     * @param syslogUUID 消息UUID
     * @param syslogTopic 消息Topic（可传 null，自动使用配置值）
     */
    public void process(String logMsg, String syslogUUID, String syslogTopic) {
        ProcessContext ctx = new ProcessContext();
        ctx.strSyslogUUID = syslogUUID;
        ctx.strSyslogTopic = (syslogTopic != null && !syslogTopic.isEmpty())
                ? syslogTopic
                : kafkaConsumerProperties.getTopic();
        ctx.isSaveNonNormal = false;
        ctx.syslogNonNormalMessage = new SyslogNonNormalMessage();

        // 解析消息
        ctx.strKafkaMessage = logMsg;
        if (!logMsg.isEmpty()) {
            ctx.strLogMsg = SyslogParser.substringAfterFirstCloseBracket(logMsg);
            ctx.strDeviceInfo = SyslogParser.substringBeforeFirstChar(logMsg, ']');
        } else {
            // 测试用例硬编码数据
            logMsg = "[receive_time=20251118165909470 device_id=1 device_name=honeypot vendor=changting data_type=json device_collect_id=1]<14>1 2025-09-24T11:52:26Z 5f46d3be75e1 supermario 128 honeypot_event - \uFEFF{\"source\":\"honeypot1\",\"id\":\"f6a13c35-bf9d-4da6-a181-50ce23e7ef6a\"}";
            ctx.strLogMsg = "<14>1 2025-09-24T11:52:26Z 5f46d3be75e1 supermario 128 honeypot_event - \uFEFF{\"source\":\"honeypot1\",\"id\":\"f6a13c35-bf9d-4da6-a181-50ce23e7ef6a\"}";
            ctx.strDeviceInfo = SyslogParser.substringBeforeFirstChar(logMsg, ']');
        }

        // 执行处理
        init(ctx);
    }

    /**
     * 初始化数据处理（所有运行时状态通过 ctx 传递，线程安全）
     */
    private void init(ProcessContext ctx) {
        Map<String, String> mapdev = SyslogParser.parseKeyValuePairs(ctx.strDeviceInfo);
        ctx.deviceInfoMap = mapdev;
        long deviceID = Long.parseLong(mapdev.get("device_id"));
        System.out.println("device_id:" + deviceID);
        ctx.strDataType = mapdev.get("data_type");
        try {
            if (deviceID > 0) {
                ctx.dmNormalizeRuleList = dmNormalizeRuleService.selectByDeviceIdAuto(deviceID);
            }
            for (int i = 0; i < ctx.dmNormalizeRuleList.size(); i++) {
                try {
                    Map<String, Object> dmNormalizeRule = ctx.dmNormalizeRuleList.get(i);
                    String data_type = dmNormalizeRule.get("data_type").toString();
                    System.out.println("索引: " + i + ", 值: " + dmNormalizeRule);
                    System.out.println("normalrule  ID: " + dmNormalizeRule.get("id")
                            + ", display_name:" + dmNormalizeRule.get("display_name")
                            + " data_type:" + dmNormalizeRule.get("data_type"));

                    ctx.OrginalColumnMap = getMessageToMap(dmNormalizeRule, ctx.strLogMsg, data_type);
                    if ((ctx.OrginalColumnMap == null) || (ctx.OrginalColumnMap.size() == 0)) {
                        logger.error("OrginalColumnMap 对象获取为空");
                        ctx.syslogNonNormalMessage.setReason("Log解析异常");
                        ctx.syslogNonNormalMessage.setReasonDetail("log解析异常,返回规则名称："
                                + dmNormalizeRule.get("display_name") + ",OrginalColumnMap 对象获取为空");
                        if (ctx.isSaveNonNormal == false)
                            SaveNonNormalMessage(ctx, deviceID, DateTime.now());
                        continue;
                    }
                    List<HashMap<String, Object>> destColumnList = getRuleContentMappers(dmNormalizeRule);
                    List<HashMap<String, Object>> ruleColumnList = getNormalColumnList(ctx.OrginalColumnMap, destColumnList);
                    Map<String, Object> destMap = getColumnMap(ruleColumnList);

                    // 数据处理-过滤规则
                    if (logDataFilterService.evaluateFilterRule(
                            dmNormalizeRule.get("rule_content").toString(), destMap))
                        continue;

                    // 数据处理-补全规则
                    logDataCompleteService.processDataCompletion(
                            dmNormalizeRule.get("rule_content").toString(), destMap);
                    SaveNormalData(ctx, deviceID, DateTime.now(), destMap,
                            Long.parseLong(dmNormalizeRule.get("id").toString()),
                            dmNormalizeRule.get("name").toString());

                } catch (Exception ex) {
                    logger.error("泛化规则处理失败：" + ex.getMessage());
                    System.out.println(ex.getMessage());
                }
            }
        } catch (Exception ex) {
            logger.error("处理日志消息异常：" + ex.getMessage());
            System.out.println(ex.getMessage());
        }
    }

    // ==================== 以下为原有业务方法 ====================

    public Cropper_paramsType getCropperParams(Map<String, Object> dmNormalizeRule) {
        Cropper_paramsType cropperParams = new Cropper_paramsType();
        try {
            JSONObject jsonObject = new JSONObject(dmNormalizeRule.get("rule_content").toString());
            if (jsonObject.isEmpty()) return null;
            cropperParams.sethead_key(jsonObject.getJSONObject("cropper_params").get("head_key").toString());
            cropperParams.sethead_offset(Integer.parseInt(
                    jsonObject.getJSONObject("cropper_params").get("head_offset").toString()));
            cropperParams.settail_key(jsonObject.getJSONObject("cropper_params").get("tail_key").toString());
            cropperParams.settail_offset(Integer.parseInt(
                    jsonObject.getJSONObject("cropper_params").get("tail_offset").toString()));
            return cropperParams;
        } catch (Exception ex) {
            logger.error("getCropperParams：" + ex.getMessage());
            return null;
        }
    }

    public List<HashMap<String, Object>> getRuleContentMappers(Map<String, Object> dmNormalizeRule) {
        List<HashMap<String, Object>> filedList = null;
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            JSONObject jsonObject = new JSONObject(dmNormalizeRule.get("rule_content").toString());
            if (jsonObject.isEmpty()) return null;
            filedList = readJsonToList(jsonObject.get("mappers").toString());
        } catch (Exception ex) {
            logger.error("getRuleContentMappers异常：" + ex.getMessage());
        }
        return filedList;
    }

    public List<HashMap<String, Object>> getCompleteColumnsList(Map<String, Object> dmNormalizeRule) {
        List<HashMap<String, Object>> filedList = null;
        try {
            JSONObject jsonObject = new JSONObject(dmNormalizeRule.get("rule_content").toString());
            if (jsonObject.isEmpty()) return null;
            filedList = readJsonToList(jsonObject.get("complete_columns").toString());
        } catch (Exception ex) {
            logger.error("getCompleteColumnsList：" + ex.getMessage());
        }
        return filedList;
    }

    public static List<HashMap<String, Object>> readJsonToList(String jsonStr) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.readValue(jsonStr,
                    new TypeReference<List<HashMap<String, Object>>>() {});
        } catch (Exception e) {
            logger.error("readJsonToList 解析失败：" + jsonStr);
            return null;
        }
    }

    public String getLogDataType(String logMsg) {
        return "json";
    }

    public int getDeviceID(String logMsg) {
        return 1;
    }

    public LinkedHashMap<String, Object> getMessageToMap(String MsgContent) {
        LinkedHashMap<String, Object> linkMap = null;
        if ("json".equals("json")) {  // 默认走 json 分支
            SyslogMessage msg = SyslogParser.parse(MsgContent);
            System.out.println("解析结果-log content: " + msg.getMessage().toString());
            String complexJson = "{\"source\":\"honeypot1\",\"id\":\"f6a13c35-bf9d-4da6-a181-50ce23e7ef6a\"}";
            System.out.println("complexJson content: " + complexJson);
            if ("dev".equals(appProperties.getRunEnvironment())) {
                LinkedHashMap<String, Object> flatMap = JsonParser.jsonToMap(complexJson);
                flatMap.forEach((key, value) -> System.out.println(key + " = " + value));
                return flatMap;
            } else {
                LinkedHashMap<String, Object> flatMap = JsonParser.jsonToMap(msg.getMessage());
                flatMap.forEach((key, value) -> System.out.println(key + " = " + value));
                return flatMap;
            }
        }
        return linkMap;
    }

    public LinkedHashMap<String, Object> getMessageToMap(
            Map<String, Object> dmNormalizeRule, String MsgContent, String dataType) {
        LinkedHashMap<String, Object> linkMap = new LinkedHashMap<>();
        try {
            Cropper_paramsType cropperParams = getCropperParams(dmNormalizeRule);
            if (dataType.equals("json")) {
                String strJson = logNormalData.ParserMessageJsonType(MsgContent, cropperParams);
                LinkedHashMap<String, Object> result1 = NestedJsonParserUtil.safeParseJson(strJson);
                LinkedHashMap<String, Object> flattened = NestedJsonUtils.flattenNestedJson(result1);
                return flattened;
            } else if (dataType.equals("kv")) {
                String strKeyVal = logNormalData.ParserMessageJsonType(MsgContent, cropperParams);
                KvTextParser kvTextParser = new KvTextParser();
                kv_paramsType kvparams = logNormalData.getkv_paramsType(dmNormalizeRule);
                linkMap = kvTextParser.parseKvText(strKeyVal, kvparams);
                return linkMap;
            } else if (dataType.equals("sep")) {
                String SepKey = logNormalData.sepType(dmNormalizeRule);
                String strSep = logNormalData.ParserMessageJsonType(MsgContent, cropperParams);
                linkMap = TextParserUtil.parseSeparatedText(strSep, SepKey);
                return linkMap;
            } else if (dataType.equals("xml")) {
                return linkMap;
            } else if (dataType.equals("regex")) {
                String strRegex = logNormalData.ParserMessageJsonType(MsgContent, cropperParams);
                String regexp = logNormalData.Regexp(dmNormalizeRule);
                linkMap = RegexTextParser.parseWithRegex(strRegex, regexp);
                return linkMap;
            }
        } catch (Exception ex) {
            logger.error("getMessageToMap：" + ex.getMessage());
            return null;
        }
        return linkMap;
    }

    public List<Map<String, Object>> getRuleList(long device_id) {
        List<Map<String, Object>> rulelst = dmNormalizeRuleService.selectByDeviceId((long) 1);
        if (rulelst != null) {
            System.out.println("rulelst: " + rulelst);
        } else {
            logger.error(" List<Map<String, Object>> rulelst is null！");
        }
        return rulelst;
    }

    public List<HashMap<String, Object>> getNormalColumnList(
            LinkedHashMap<String, Object> orginColumnMap,
            List<HashMap<String, Object>> destColumnList) {
        List<HashMap<String, Object>> columnlist = new ArrayList<>();
        for (Map.Entry<String, Object> entry : orginColumnMap.entrySet()) {
            for (Map<String, Object> map : destColumnList) {
                if (map.get("origin_field").toString().equals(entry.getKey())) {
                    System.out.println(map);
                    Map<String, Object> normalColumMap = new LinkedHashMap<>();
                    normalColumMap.put("origin_field", entry.getKey());
                    normalColumMap.put("dest_field", map.get("dest_field").toString());
                    normalColumMap.put("action", (HashMap<String, Object>) map.get("action"));
                    normalColumMap.put("origin_field_value", entry.getValue());
                    if (((HashMap<String, Object>) map.get("action")).get("type").equals("equal")) {
                        normalColumMap.put("dest_field_value", entry.getValue());
                    } else if (((HashMap<String, Object>) map.get("action")).get("type").equals("mapping")) {
                        normalColumMap.put("action_param",
                                ((HashMap<String, Object>) map.get("action")).get("param"));
                        HashMap<String, Object> action_param =
                                (HashMap<String, Object>) ((HashMap<String, Object>) map.get("action")).get("param");
                        normalColumMap.put("dest_field_value",
                                getMappingValue(action_param, entry.getValue().toString()));
                    } else if (((HashMap<String, Object>) map.get("action")).get("type").equals("time")) {
                        normalColumMap.put("action_param",
                                ((HashMap<String, Object>) map.get("action")).get("param"));
                        HashMap<String, Object> action_param =
                                (HashMap<String, Object>) ((HashMap<String, Object>) map.get("action")).get("param");
                        try {
                            long longTime = TimeConversionUtils.convertToMillis(
                                    entry.getValue().toString(), action_param.get("timezone").toString());
                            normalColumMap.put("dest_field_value", longTime);
                        } catch (Exception e) {
                            logger.error("时间类型转换错误，源值：" + entry.getValue().toString()
                                    + ",java_date_format:" + action_param.get("java_date_format").toString());
                            e.printStackTrace();
                        }
                    }
                    columnlist.add((HashMap<String, Object>) normalColumMap);
                    continue;
                }
            }
        }
        return columnlist;
    }

    public Object getMappingValue(HashMap<String, Object> paramMappingValueMap, String value) {
        HashMap<String, Object> Map = (HashMap<String, Object>) paramMappingValueMap.get("mapping");
        for (Map.Entry<String, Object> entry : Map.entrySet()) {
            if (entry.getKey().equals(value)) {
                return entry.getValue();
            }
        }
        return null;
    }

    public Map<String, Object> getColumnMap(List<HashMap<String, Object>> normalColumnList) {
        Map<String, Object> columnMap = new HashMap<>();
        for (Map<String, Object> map : normalColumnList) {
            Object destFieldValue = map.get("dest_field_value");
            if (destFieldValue instanceof String
                    && ((String) destFieldValue).contains("\u0000")) {
                destFieldValue = ((String) destFieldValue).replace("\u0000", "");
            }
            columnMap.put(map.get("dest_field").toString(), destFieldValue);
        }
        return columnMap;
    }

    public void SaveNormalData(ProcessContext ctx, long deviceId, DateTime logtime,
                               Map<String, Object> logColumnMap,
                               long normalizeRuleId, String normalizeRuleName) {
        try {
            if (logColumnMap.isEmpty()) {
                logger.error("SaveNormalData ->logColumnMap 为空，syslogUUID:" + ctx.strSyslogUUID);
                ctx.syslogNonNormalMessage.setReason("未命中规则");
                ctx.syslogNonNormalMessage.setReasonDetail("失败详情：logColumnMap对象字段为空");
                if (ctx.isSaveNonNormal == false)
                    SaveNonNormalMessage(ctx, deviceId, DateTime.now());
                return;
            }
            Map<String, Object> columnMap = logColumnMap;
            //补全采集设备信息
            CompletionDeviceInfo(columnMap, deviceId);
            //补全采集探针相关信息
            CompletionCollectTaskInfo(columnMap,ctx);
            //补全日志基础信息
            columnMap.put("device_id", deviceId);
            columnMap.put("log_time", logtime);
            columnMap.put("id", UUID.randomUUID().toString());
            columnMap.put("normalize_rule_id", normalizeRuleId);
            columnMap.put("normalize_rule_name", normalizeRuleName);
            columnMap.put("syslog_uuid", ctx.strSyslogUUID);
            columnMap.put("syslog_topic", ctx.strSyslogTopic);
            System.out.println("columnMap：" + columnMap);
            syslogNormalDataService.insertDynamic(columnMap);
        } catch (Exception e) {
            logger.error("SaveNormalData失败 ");
            ctx.syslogNonNormalMessage.setReason("入库失败");
            ctx.syslogNonNormalMessage.setReasonDetail("入库失败,normalizeRuleName :" + normalizeRuleName
                    + ",失败详情：" + e.getMessage());
            if (ctx.isSaveNonNormal == false)
                SaveNonNormalMessage(ctx, deviceId, DateTime.now());
            throw new RuntimeException("SaveNormalData 失败: " + e.getMessage(), e);
        }
    }
    //补全采集设备信息
    public void CompletionDeviceInfo(Map<String, Object> columnMap, Long deviceID) {
        try {
            DeviceDevice devInfo = deviceDeviceService.getByIdSafely(Long.valueOf(deviceID).intValue());
            if (devInfo != null) {
                columnMap.put("device_ip", devInfo.getIp());
                columnMap.put("device_manufacturer", devInfo.getVendor());
                columnMap.put("device_name", devInfo.getName());
            }
        } catch (Exception e) {
            logger.error("CompletionDeviceInfo 失败！ID：" + deviceID);
        }
    }

    //补全采集探针相关信息（ID、IP、名称)
    public void CompletionCollectTaskInfo(Map<String, Object> columnMap,ProcessContext ctx) {
        Integer collect_id=-1;
        try {
            collect_id = Integer.parseInt(ctx.deviceInfoMap.get("device_collect_id"));
            DeviceCollectTask deviceCollectTask = deviceCollectTaskService.getById(collect_id);
            if (deviceCollectTask != null) {
                columnMap.put("agent_id", collect_id);
                columnMap.put("origin_agent_id",collect_id.toString() );
                columnMap.put("probe_ip",deviceCollectTask.getDeviceIp() );
                columnMap.put("agent_name", deviceCollectTask.getTaskName());
                columnMap.put("origin_agent_name", deviceCollectTask.getTaskName());
            }
        } catch (Exception e) {
            logger.error("CompletionCollectTaskInfo 失败！探针ID：" + collect_id);
        }
    }

    public void SaveNonNormalMessage(ProcessContext ctx, long deviceId, DateTime logtime) {
        try {
            SyslogNonNormalMessage normalMessage = new SyslogNonNormalMessage();
            Integer collect_id = Integer.parseInt(ctx.deviceInfoMap.get("device_collect_id"));
            DeviceCollectTask deviceCollectTask = deviceCollectTaskService.getById(collect_id);
            normalMessage.setId(UUID.randomUUID().toString());
            normalMessage.setDeviceId((int) deviceId);
            normalMessage.setLogTime(logtime.toLocalDateTime());
            normalMessage.setRuleTime(logtime.toLocalDateTime());
            normalMessage.setSyslogMessage(ctx.strLogMsg);
            normalMessage.setSyslogTopic(ctx.strSyslogTopic);
            normalMessage.setSyslogUuid(ctx.strSyslogUUID);
            normalMessage.setHeaderMessage(ctx.strDeviceInfo);
            normalMessage.setEtlNode("etlgo");
            normalMessage.setReason(ctx.syslogNonNormalMessage.getReason());
            normalMessage.setReasonDetail(ctx.syslogNonNormalMessage.getReasonDetail());
            normalMessage.setRuleResult("FAIL");
            normalMessage.setDeviceName(ctx.deviceInfoMap.get("device_name"));
            normalMessage.setCollectTaskId(collect_id);
            if (deviceCollectTask != null)
                normalMessage.setCollectTaskName(deviceCollectTask.getTaskName());
            this.messageService.saveMessage(normalMessage);
            ctx.isSaveNonNormal = true;
        } catch (Exception e) {
            logger.error("SaveNonNormalMessage  失败：");
            throw new RuntimeException("SaveNonNormalMessage 失败: " + e.getMessage(), e);
        }
    }

}
