package com.ruoyi.ccdi.project.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.ccdi.project.domain.entity.CcdiProjectOverviewEmployeeResult;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

class CcdiProjectOverviewEmployeeResultBuilderTest {

    @Test
    @SuppressWarnings("unchecked")
    void shouldAggregateHitRowsIntoEmployeeResultSnapshots() throws Exception {
        Class<?> rowClass = Class.forName("com.ruoyi.ccdi.project.domain.vo.CcdiProjectOverviewEmployeeHitRowVO");
        Class<?> builderClass = Class.forName("com.ruoyi.ccdi.project.service.impl.CcdiProjectOverviewEmployeeResultBuilder");

        Object builder = builderClass.getDeclaredConstructor().newInstance();
        Method buildMethod = builderClass.getMethod("build", Long.class, List.class, String.class);

        List<Object> hitRows = List.of(
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "LARGE_TRANSACTION", "大额交易", "HOUSE_OR_CAR_EXPENSE", "房车消费支出交易", "HIGH"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "LARGE_TRANSACTION", "大额交易", "HOUSE_OR_CAR_EXPENSE", "房车消费支出交易", "HIGH"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "LARGE_TRANSACTION", "大额交易", "TAX_EXPENSE", "税务支出交易", "HIGH"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "ABNORMAL_TRANSACTION", "异常交易", "ABNORMAL_CUSTOMER_TRANSACTION", "异常客户交易", "HIGH"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "ABNORMAL_TRANSACTION", "异常交易", "ABNORMAL_CUSTOMER_TRANSACTION", "异常客户交易", "HIGH"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "SUSPICIOUS_PART_TIME", "可疑兼职", "MONTHLY_FIXED_INCOME", "疑似兼职", "MEDIUM"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "SUSPICIOUS_PROPERTY", "可疑财产", "HOUSE_REGISTRATION_MISMATCH", "房产登记不匹配", "LOW"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "ABNORMAL_ACCOUNT", "异常账户", "SUDDEN_ACCOUNT_CLOSURE", "突然销户", "HIGH"),
            buildHitRow(rowClass, "330000000000000001", "李四", "E1001", 12L, "信息二部",
                "ABNORMAL_ACCOUNT", "异常账户", "DORMANT_ACCOUNT_LARGE_ACTIVATION", "休眠账户大额启用", "HIGH")
        );

        List<CcdiProjectOverviewEmployeeResult> results =
            (List<CcdiProjectOverviewEmployeeResult>) buildMethod.invoke(builder, 40L, hitRows, "tester");

        assertEquals(1, results.size());
        CcdiProjectOverviewEmployeeResult result = results.getFirst();
        assertEquals(40L, result.getProjectId());
        assertEquals("330000000000000001", result.getStaffIdCard());
        assertEquals("李四", result.getStaffName());
        assertEquals("E1001", result.getStaffCode());
        assertEquals(12L, result.getDeptId());
        assertEquals("信息二部", result.getDeptName());
        assertEquals(7, result.getRuleCount());
        assertEquals(5, result.getModelCount());
        assertEquals(9, result.getHitCount());
        assertEquals("HIGH", result.getRiskLevelCode());
        assertEquals("ABNORMAL_ACCOUNT,ABNORMAL_TRANSACTION,LARGE_TRANSACTION,SUSPICIOUS_PART_TIME,SUSPICIOUS_PROPERTY",
            result.getModelCodesCsv());
        assertNotNull(result.getRiskPoint());

        JSONArray modelNames = JSON.parseArray(result.getModelNamesJson());
        assertEquals(List.of("异常账户", "异常交易", "大额交易", "可疑兼职", "可疑财产"),
            modelNames.toList(String.class));

        JSONArray hitRules = JSON.parseArray(result.getHitRulesJson());
        assertEquals(7, hitRules.size());
        assertTrue(result.getHitRulesJson().contains("SUDDEN_ACCOUNT_CLOSURE"));
        assertTrue(result.getHitRulesJson().contains("DORMANT_ACCOUNT_LARGE_ACTIVATION"));
        JSONObject firstRule = hitRules.getJSONObject(0);
        assertEquals("ABNORMAL_CUSTOMER_TRANSACTION", firstRule.getString("ruleCode"));
        assertEquals("异常客户交易", firstRule.getString("ruleName"));
        assertEquals("HIGH", firstRule.getString("riskLevel"));
        assertEquals(2, firstRule.getIntValue("warningCount"));

        JSONArray modelSummary = JSON.parseArray(result.getModelHitSummaryJson());
        Map<String, Integer> warningCountByModel = modelSummary.toList(JSONObject.class).stream()
            .collect(java.util.stream.Collectors.toMap(
                item -> item.getString("modelCode"),
                item -> item.getIntValue("warningCount")
            ));
        assertEquals(2, warningCountByModel.get("ABNORMAL_ACCOUNT"));
        assertEquals(2, warningCountByModel.get("ABNORMAL_TRANSACTION"));
        assertEquals(3, warningCountByModel.get("LARGE_TRANSACTION"));
        assertEquals(1, warningCountByModel.get("SUSPICIOUS_PROPERTY"));
        assertEquals(1, warningCountByModel.get("SUSPICIOUS_PART_TIME"));
    }

    private Object buildHitRow(Class<?> rowClass,
                               String staffIdCard,
                               String staffName,
                               String staffCode,
                               Long deptId,
                               String deptName,
                               String modelCode,
                               String modelName,
                               String ruleCode,
                               String ruleName,
                               String riskLevel) throws Exception {
        Object row = rowClass.getDeclaredConstructor().newInstance();
        setField(rowClass, row, "setProjectId", Long.class, 40L);
        setField(rowClass, row, "setStaffIdCard", String.class, staffIdCard);
        setField(rowClass, row, "setStaffName", String.class, staffName);
        setField(rowClass, row, "setStaffCode", String.class, staffCode);
        setField(rowClass, row, "setDeptId", Long.class, deptId);
        setField(rowClass, row, "setDeptName", String.class, deptName);
        setField(rowClass, row, "setModelCode", String.class, modelCode);
        setField(rowClass, row, "setModelName", String.class, modelName);
        setField(rowClass, row, "setRuleCode", String.class, ruleCode);
        setField(rowClass, row, "setRuleName", String.class, ruleName);
        setField(rowClass, row, "setRiskLevel", String.class, riskLevel);
        return row;
    }

    private void setField(Class<?> rowClass, Object row, String methodName, Class<?> parameterType, Object value)
        throws Exception {
        Method method = rowClass.getMethod(methodName, parameterType);
        method.invoke(row, value);
    }
}
