package com.common.service.impl;

import com.common.entity.*;
import com.common.mapper.*;
import com.common.service.AnalysisEngine;
import com.common.service.SqlGeneratorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 离线分析引擎实现
 */
@Slf4j
@Service("offlineAnalysisEngine")
public class OfflineAnalysisEngine implements AnalysisEngine {

    @Autowired
    private SqlGeneratorService sqlGeneratorService;

    @Autowired
    private AnalysisAnalysisRuleMapper ruleMapper;

    @Autowired
    private AnalysisFieldMapper fieldMapper;

    @Autowired
    private AnalysisWhereConditionMapper whereConditionMapper;

    @Autowired
    private AnalysisGroupByColumnMapper groupByColumnMapper;

    @Autowired
    private AnalysisFilterMapper filterMapper;

    @Autowired
    private AnalysisGroupByHavingMapper groupByHavingMapper;
    @Autowired
    private AnalysisGroupByMapper groupByMapper;

    @Autowired
    private AnalysisGroupByWindowMapper groupByWindowMapper;


    @Autowired
    private AnalysisTaskHistoryMapper taskHistoryMapper;

    @Autowired
    private AlarmMapper alarmMapper;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static final String RUN_MODE = "offline";
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public Map<String, Object> executeRule(AnalysisAnalysisRule rule) {
        String batchNo = generateBatchNo();
        LocalDateTime startTime = LocalDateTime.now();

        log.info("开始执行离线规则: ruleId={}, ruleName={}, batchNo={}",
                rule.getRuleId(), rule.getRuleName(), batchNo);

        // 从规则配置中获取时间范围
        LocalDateTime dataStartTime = parseDataStartTime(rule);
        LocalDateTime dataEndTime = parseDataEndTime(rule);

        // 如果配置中没有指定时间范围，使用默认值
        if (dataStartTime == null) {
            dataStartTime = startTime.minusHours(1);
        }
        if (dataEndTime == null) {
            dataEndTime = startTime;
        }

        // 创建任务历史记录
        AnalysisTaskHistory history = AnalysisTaskHistory.builder()
                .id(System.currentTimeMillis()) // 使用时间戳作为ID
                .ruleId(rule.getRuleId())
                .startTime(startTime)
                .status("RUNNING")
                .progressPercent(0)
                .inputCount(0L)
                .outputCount(0L)
                .delFlag("0")
                .createTime(startTime)
                .updateTime(startTime)
                .tenantId("000000")
                .remark("离线分析任务 - " + batchNo)
                .build();
        taskHistoryMapper.insert(history);

        Map<String, Object> result = new HashMap<>();
        result.put("ruleId", rule.getRuleId());
        result.put("ruleName", rule.getRuleName());
        result.put("runMode", RUN_MODE);
        result.put("batchNo", batchNo);
        result.put("dataStartTime", dataStartTime);
        result.put("dataEndTime", dataEndTime);

        try {
            // 更新规则状态为运行中
            ruleMapper.updateTaskStatus(rule.getRuleId(), "running", 1L);

            // 加载规则配置
            List<AnalysisField> fields = fieldMapper.selectByRuleId(rule.getRuleId());
            List<AnalysisWhereCondition> whereConditions = whereConditionMapper.selectByRuleId(rule.getRuleId());
            List<AnalysisFilter> filters = filterMapper.selectByRuleId(rule.getRuleId());
            List<AnalysisGroupByColumn> groupByColumns = groupByColumnMapper.selectByRuleId(rule.getRuleId());
            List<AnalysisGroupByHaving> havingConditions = groupByHavingMapper.selectByRuleId(rule.getRuleId());


            // 加载分组和窗口配置
            AnalysisGroupByWindow groupByWindow = null;
            List<AnalysisGroupBy> groupByList = groupByMapper.selectByRuleId(rule.getRuleId());
            if (groupByList != null && !groupByList.isEmpty()) {
                AnalysisGroupBy groupBy = groupByList.get(0);
                if (groupBy.getId() != null) {
                    groupByWindow = groupByWindowMapper.selectByGroupById(groupBy.getId().intValue());
                }
            }
            // 生成SQL
            String sql = sqlGeneratorService.generateSql(
                    rule,
                    fields,
                    whereConditions,
                    filters,
                    groupByColumns,
                    havingConditions,
                    groupByWindow,
                    dataStartTime.format(DATE_FORMATTER),
                    dataEndTime.format(DATE_FORMATTER)
            );

            log.info("生成的SQL: {}", sql);

            // 执行SQL
            List<Map<String, Object>> queryResult = jdbcTemplate.queryForList(sql);
            result.put("queryResult", queryResult);

            // 处理结果，生成告警
            long alarmCount = 0;
            if (!queryResult.isEmpty()) {
                List<Alarm> alarms = convertToAlarms(rule, queryResult);
                if (!alarms.isEmpty()) {
                    //String tableName = "alarm_" + dataStartTime.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                    String tableName = "alarm";
                    alarmMapper.batchInsert( alarms);
                    alarmCount = alarms.size();
                }
            }

            // 更新任务历史
            LocalDateTime endTime = LocalDateTime.now();
            long durationSeconds = java.time.Duration.between(startTime, endTime).getSeconds();
            history.setEndTime(endTime);
            history.setDurationTime(durationSeconds);
            history.setProgressPercent(100);
            history.setInputCount((long) queryResult.size());
            history.setOutputCount(alarmCount);
            history.setStatus("COMPLETED");
            history.setUpdateTime(endTime);
            taskHistoryMapper.update(history);

            result.put("processedCount", queryResult.size());
            result.put("alarmCount", alarmCount);
            result.put("status", "success");

            // 更新规则状态为等待
            ruleMapper.updateTaskStatus(rule.getRuleId(), "waiting", 1L);

            log.info("规则执行成功: ruleId={}, processedCount={}, alarmCount={}",
                    rule.getRuleId(), queryResult.size(), alarmCount);

        } catch (Exception e) {
            log.error("规则执行失败: ruleId={}", rule.getRuleId(), e);

            // 更新任务历史
            LocalDateTime endTime = LocalDateTime.now();
            long durationSeconds = java.time.Duration.between(startTime, endTime).getSeconds();
            history.setEndTime(endTime);
            history.setDurationTime(durationSeconds);
            history.setStatus("FAILED");
            //history.setRemark("执行失败: " + e.getMessage());
            history.setRemark("执行失败: " + (e.getMessage().length()>480? e.getMessage().substring(0,480):e.getMessage()));
            history.setUpdateTime(endTime);
            taskHistoryMapper.update(history);

            // 更新规则状态
            ruleMapper.updateTaskStatus(rule.getRuleId(), "stopped", 1L);

            result.put("status", "failed");
            result.put("errorMsg", e.getMessage());
        }

        return result;
    }

    @Override
    public List<Map<String, Object>> executeRules(List<AnalysisAnalysisRule> rules) {
        List<Map<String, Object>> results = new ArrayList<>();

        for (AnalysisAnalysisRule rule : rules) {
            try {
                Map<String, Object> result = executeRule(rule);
                results.add(result);
            } catch (Exception e) {
                log.error("执行规则失败: ruleId={}", rule.getRuleId(), e);
                Map<String, Object> errorResult = new HashMap<>();
                errorResult.put("ruleId", rule.getRuleId());
                errorResult.put("ruleName", rule.getRuleName());
                errorResult.put("status", "failed");
                errorResult.put("errorMsg", e.getMessage());
                results.add(errorResult);
            }
        }

        return results;
    }

    @Override
    public void stopRule(String ruleId) {
        try {
            ruleMapper.updateTaskStatus(ruleId, "stopped", 1L);
            log.info("已停止规则: ruleId={}", ruleId);
        } catch (Exception e) {
            log.error("停止规则失败: ruleId={}", ruleId, e);
        }
    }

    @Override
    public String getRunMode() {
        return RUN_MODE;
    }

    /**
     * 生成批次号
     */
    private String generateBatchNo() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
    }

    /**
     * 解析数据开始时间
     */
    private LocalDateTime parseDataStartTime(AnalysisAnalysisRule rule) {
        // 从rule_content或rule_expression中解析时间范围
        // 这里简化处理，实际需要解析JSON配置
/*        if (StringUtils.isNotBlank(rule.getRuleContent())) {
            // TODO: 解析JSON配置获取时间范围
        }*/
        return null;
    }

    /**
     * 解析数据结束时间
     */
    private LocalDateTime parseDataEndTime(AnalysisAnalysisRule rule) {
        // 从rule_content或rule_expression中解析时间范围
/*        if (StringUtils.isNotBlank(rule.getRuleContent())) {
            // TODO: 解析JSON配置获取时间范围
        }*/
        return null;
    }

    /**
     * 转换查询结果为告警对象
     * 复用实时引擎的转换逻辑
     */
    private List<Alarm> convertToAlarms(AnalysisAnalysisRule rule, List<Map<String, Object>> queryResult) {
        List<Alarm> alarms = new ArrayList<>();

        for (Map<String, Object> row : queryResult) {
            Alarm alarm = Alarm.builder()
                    .id(UUID.randomUUID().toString())
                    .createdAt(LocalDateTime.now())
                    .updatedAt(LocalDateTime.now())
                    .alarmName(rule.getRuleName())
                    .engineType("offline")
                    .attackResult(-1)
                    .focused(false)
                    .fall(0)
                    .alarmLevel("未知")
                    .baseFocused(false)
                    .isUpdated(false)
                    .alarmSource(1)
                    .dispositionAdvice("研判后处置")
                    .disposedState(0)
                    .attackDirection("other")
                    .etlTime(LocalDateTime.now())
                    .alarmAreaId(0)
                    .build();

            // 映射查询结果字段到告警对象（根据新表结构）
            if (row.containsKey("log_start_at")) {
                alarm.setLogStartAt(getTimestampValue(row.get("log_start_at")));
            }
            if (row.containsKey("log_end_at")) {
                alarm.setLogEndAt(getTimestampValue(row.get("log_end_at")));
            }
            if (row.containsKey("alarm_name")) {
                alarm.setComment(getStringValue(row.get("alarm_name")));
            }
            if (row.containsKey("alarm_type")) {
                alarm.setComment(getStringValue(row.get("alarm_type")));
            }
            if (row.containsKey("alarm_level")) {
                alarm.setAlarmLevel(convertAlarmLevel(getIntegerValue(row.get("alarm_level"))));
            }
            if (row.containsKey("attack_ip")) {
                alarm.setAttackIp(getStringArray(row.get("attack_ip")));
            }
            if (row.containsKey("victim_ip")) {
                alarm.setVictimIp(getStringArray(row.get("victim_ip")));
            }
            if (row.containsKey("victim_web_url")) {
                alarm.setVictimWebUrl(getStringArray(row.get("victim_web_url")));
            }
            if (row.containsKey("attack_chain_phase")) {
                alarm.setAttackChainPhase(getIntegerArray(row.get("attack_chain_phase")));
            }
            if (row.containsKey("device_id")) {
                alarm.setDeviceId(getIntegerArray(row.get("device_id")));
            }
            if (row.containsKey("tag")) {
                alarm.setTag(getStringArray(row.get("tag")));
            }
            if (row.containsKey("comment")) {
                alarm.setComment(getStringValue(row.get("comment")));
            }
            if (row.containsKey("origin_log_ids")) {
                alarm.setOriginLogIds(getStringArray(row.get("origin_log_ids")));
            }
            if (row.containsKey("query_id")) {
                alarm.setQueryId(getStringValue(row.get("query_id")));
            }
            if (row.containsKey("attack_result")) {
                alarm.setAttackResult(getIntegerValue(row.get("attack_result")));
            }
            if (row.containsKey("fall")) {
                alarm.setFall(getIntegerValue(row.get("fall")));
            }
            if (row.containsKey("payload")) {
                alarm.setPayload(getBytesValue(row.get("payload")));
            }
            if (row.containsKey("operate_event")) {
                alarm.setOperateEvent(getIntegerArray(row.get("operate_event")));
            }
            if (row.containsKey("attack_port")) {
                alarm.setAttackPort(getIntegerArray(row.get("attack_port")));
            }
            if (row.containsKey("victim_port")) {
                alarm.setVictimPort(getIntegerArray(row.get("victim_port")));
            }
            if (row.containsKey("attack_method")) {
                alarm.setAttackMethod(getStringValue(row.get("attack_method")));
            }
            if (row.containsKey("business_ext")) {
                alarm.setBusinessExt(getStringValue(row.get("business_ext")));
            }
            if (row.containsKey("http_status")) {
                alarm.setHttpStatus(getStringValue(row.get("http_status")));
            }
            if (row.containsKey("dns_info")) {
                alarm.setDnsInfo(getStringValue(row.get("dns_info")));
            }
            if (row.containsKey("account_info")) {
                alarm.setAccountInfo(getStringValue(row.get("account_info")));
            }
            if (row.containsKey("attacker_info")) {
                alarm.setAttackerInfo(getStringValue(row.get("attacker_info")));
            }
            if (row.containsKey("victim_info")) {
                alarm.setVictimInfo(getStringValue(row.get("victim_info")));
            }
            if (row.containsKey("suspicious_action")) {
                alarm.setSuspiciousAction(getStringValue(row.get("suspicious_action")));
            }
            if (row.containsKey("vuln_info")) {
                alarm.setVulnInfo(getStringValue(row.get("vuln_info")));
            }
            if (row.containsKey("weak_pwd")) {
                alarm.setWeakPwd(getStringValue(row.get("weak_pwd")));
            }
            if (row.containsKey("compliance_baseline")) {
                alarm.setComplianceBaseline(getStringValue(row.get("compliance_baseline")));
            }
            if (row.containsKey("file_info")) {
                alarm.setFileInfo(getStringValue(row.get("file_info")));
            }
            if (row.containsKey("file_tags")) {
                alarm.setFileTags(getStringValue(row.get("file_tags")));
            }
            if (row.containsKey("endpoint_info")) {
                alarm.setEndpointInfo(getStringValue(row.get("endpoint_info")));
            }
            if (row.containsKey("origin_info")) {
                alarm.setOriginInfo(getStringValue(row.get("origin_info")));
            }
            if (row.containsKey("protocol_info")) {
                alarm.setProtocolInfo(getStringValue(row.get("protocol_info")));
            }
            if (row.containsKey("email_info")) {
                alarm.setEmailInfo(getStringValue(row.get("email_info")));
            }
            if (row.containsKey("sensitive_data")) {
                alarm.setSensitiveData(getStringValue(row.get("sensitive_data")));
            }
            if (row.containsKey("hit_intelligence")) {
                alarm.setHitIntelligence(getIntegerValue(row.get("hit_intelligence")));
            }
            if (row.containsKey("window_time")) {
                alarm.setWindowTime(getStringValue(row.get("window_time")));
            }
            if (row.containsKey("attack_ip_pic")) {
                alarm.setAttackIpPic(getStringValue(row.get("attack_ip_pic")));
            }
            if (row.containsKey("victim_ip_pic")) {
                alarm.setVictimIpPic(getStringValue(row.get("victim_ip_pic")));
            }
            if (row.containsKey("operation_at")) {
                alarm.setOperationAt(getTimestampValue(row.get("operation_at")));
            }
            if (row.containsKey("attack_direction")) {
                alarm.setAttackDirection(getStringValue(row.get("attack_direction")));
            }
            if (row.containsKey("etl_time")) {
                alarm.setEtlTime(getTimestampValue(row.get("etl_time")));
            }
            if (row.containsKey("log_count")) {
                alarm.setLogCount(getIntegerValue(row.get("log_count")));
            }
            if (row.containsKey("is_asset_hit")) {
                alarm.setIsAssetHit(getIntegerValue(row.get("is_asset_hit")));
            }
            if (row.containsKey("http_req_header")) {
                alarm.setHttpReqHeader(getStringArray(row.get("http_req_header")));
            }
            if (row.containsKey("http_req_body")) {
                alarm.setHttpReqBody(getStringArray(row.get("http_req_body")));
            }
            if (row.containsKey("http_resp_header")) {
                alarm.setHttpRespHeader(getStringArray(row.get("http_resp_header")));
            }
            if (row.containsKey("http_resp_body")) {
                alarm.setHttpRespBody(getStringArray(row.get("http_resp_body")));
            }
            if (row.containsKey("window_time")) {
                alarm.setLogEndAt(getTimestampValue(row.get("window_time")));
            }
            alarms.add(alarm);
        }

        return alarms;
    }

    private byte[] getBytesValue(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof byte[]) {
            return (byte[]) value;
        }
        return value.toString().getBytes();
    }

    // 以下为辅助方法，用于类型转换

    private String getStringValue(Object value) {
        if (value == null) {
            return null;
        }
        return value.toString();
    }

    private Long getLongValue(Object value) {
        if (value == null) {
            return 0L;
        }
        if (value instanceof Number) {
            return ((Number) value).longValue();
        }
        return Long.parseLong(value.toString());
    }

    private Integer getIntegerValue(Object value) {
        if (value == null) {
            return 0;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        return Integer.parseInt(value.toString());
    }

    private LocalDateTime getTimestampValue(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof LocalDateTime) {
            return (LocalDateTime) value;
        }
        return LocalDateTime.parse(value.toString());
    }

    @SuppressWarnings("unchecked")
    private String[] getStringArray(Object value) {
        if (value == null) {
            return new String[0];
        }
        if (value instanceof String[]) {
            return (String[]) value;
        }
        if (value instanceof Object[]) {
            Object[] arr = (Object[]) value;
            String[] result = new String[arr.length];
            for (int i = 0; i < arr.length; i++) {
                result[i] = arr[i] != null ? arr[i].toString() : null;
            }
            return result;
        }
        String str = value.toString();
        if (str.startsWith("{") && str.endsWith("}")) {
            str = str.substring(1, str.length() - 1);
            return str.split(",");
        }
        return new String[]{str};
    }

    @SuppressWarnings("unchecked")
    private Integer[] getIntegerArray(Object value) {
        if (value == null) {
            return new Integer[0];
        }
        String[] strArray = getStringArray(value);
        Integer[] result = new Integer[strArray.length];
        for (int i = 0; i < strArray.length; i++) {
            try {
                result[i] = Integer.parseInt(strArray[i]);
            } catch (NumberFormatException e) {
                result[i] = null;
            }
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    private byte[][] getByteArrayArray(Object value) {
        if (value == null) {
            return new byte[0][];
        }
        if (value instanceof byte[][]) {
            return (byte[][]) value;
        }
        if (value instanceof Object[]) {
            Object[] arr = (Object[]) value;
            byte[][] result = new byte[arr.length][];
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] instanceof byte[]) {
                    result[i] = (byte[]) arr[i];
                } else {
                    result[i] = arr[i] != null ? arr[i].toString().getBytes() : null;
                }
            }
            return result;
        }
        return new byte[0][];
    }

    private String convertAlarmLevel(Integer eventLevel) {
        if (eventLevel == null) return "未知";
        switch (eventLevel) {
            case 0: return "安全(无威胁)";
            case 1: return "低危";
            case 2: return "中危";
            case 3: return "高危";
            case 4: return "超危";
            default: return "未知";
        }
    }
}
