package com.cf.imes.module.system.util.collection;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;

import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

/**
 * {@link SimpleTrie} 的单元测试
 */
class SimpleTrieTest {

    private SimpleTrie simpleTrie;

    @BeforeEach
    void setUp() {
        List<String> sensitiveWords = Arrays.asList("敏感词", "测试", "ABC", "暴力", "暴力行为");
        simpleTrie = new SimpleTrie(sensitiveWords);
    }

    @Test
    void testConstructorWithEmptyCollection() {
        // 测试空集合构造
        SimpleTrie trie = new SimpleTrie(Collections.emptyList());
        assertTrue(trie.isValid("任何文本"));
        assertTrue(trie.validate("任何文本").isEmpty());
    }

    @Test
    void testIsValidWithValidText() {
        // 测试不包含敏感词的文本
        assertTrue(simpleTrie.isValid("这是一段正常的文本"));
        assertTrue(simpleTrie.isValid(""));
        assertTrue(simpleTrie.isValid(" "));
    }

    @Test
    void testIsValidWithInvalidText() {
        // 测试包含敏感词的文本
        assertFalse(simpleTrie.isValid("这段文本包含敏感词"));
        assertFalse(simpleTrie.isValid("测试文本"));
        assertFalse(simpleTrie.isValid("ABC"));
        assertFalse(simpleTrie.isValid("暴力行为"));
    }

    @Test
    void testIsValidWithPartialMatch() {
        // 测试部分匹配的情况
        assertTrue(simpleTrie.isValid("敏感情")); // "敏感情"不包含敏感词"敏感词"
        assertTrue(simpleTrie.isValid("测验"));   // "测验"不包含敏感词"测试"
        assertFalse(simpleTrie.isValid("ABCD"));  // "ABCD"包含敏感词"ABC"
        assertFalse(simpleTrie.isValid("暴力事件")); // "暴力事件"包含敏感词"暴力"
    }

    @Test
    void testValidateWithValidText() {
        // 测试不包含敏感词的文本
        List<String> result = simpleTrie.validate("这是一段正常的文本");
        assertTrue(result.isEmpty());

        result = simpleTrie.validate("");
        assertTrue(result.isEmpty());

        result = simpleTrie.validate(" ");
        assertTrue(result.isEmpty());
    }

    @Test
    void testValidateWithSingleSensitiveWord() {
        // 测试包含单个敏感词的文本
        List<String> result = simpleTrie.validate("这段文本包含敏感词");
        assertEquals(1, result.size());
        assertTrue(result.contains("敏感词"));

        result = simpleTrie.validate("测试文本");
        assertEquals(1, result.size());
        assertTrue(result.contains("测试"));

        result = simpleTrie.validate("ABC");
        assertEquals(1, result.size());
        assertTrue(result.contains("ABC"));
    }

    @Test
    void testValidateWithMultipleSensitiveWords() {
        // 测试包含多个敏感词的文本
        List<String> result = simpleTrie.validate("这段文本包含敏感词和测试内容");
        assertEquals(2, result.size());
        assertTrue(result.contains("敏感词"));
        assertTrue(result.contains("测试"));
    }

    @Test
    void testValidateWithOverlappingSensitiveWords() {
        // 测试包含重叠敏感词的文本（最短匹配原则）
        List<String> result = simpleTrie.validate("暴力行为测试");
        assertEquals(2, result.size());
        assertTrue(result.contains("暴力")); // 最短匹配
        assertTrue(result.contains("测试"));
        
        // 验证不会同时返回"暴力"和"暴力行为"
        assertFalse(result.contains("暴力") && result.contains("暴力行为"));
    }

    @Test
    void testValidateWithRepeatedSensitiveWords() {
        // 测试重复敏感词的情况
        List<String> result = simpleTrie.validate("测试测试测试");
        assertEquals(1, result.size()); // 应该去重
        assertTrue(result.contains("测试"));
    }

    @Test
    void testShortestMatchPrinciple() {
        // 测试最短匹配原则
        List<String> words = Arrays.asList("煞笔", "煞笔二货");
        SimpleTrie trie = new SimpleTrie(words);
        
        List<String> result = trie.validate("这个人是个煞笔二货");
        assertEquals(1, result.size());
        assertTrue(result.contains("煞笔")); // 应该只返回最短的匹配
        assertFalse(result.contains("煞笔二货"));
    }

    @Test
    void testPrefixOptimization() {
        // 测试前缀优化：如果已有较短敏感词，不应再添加更长的以相同前缀开始的词
        List<String> words = Arrays.asList("吃饭", "吃饭啊");
        SimpleTrie trie = new SimpleTrie(words);
        
        // 验证"吃饭啊"实际上没有被完全添加（因为已经有"吃饭"）
        // 但"吃饭"已经被添加，所以包含"吃饭"的文本应该验证失败
        assertFalse(trie.isValid("我要吃饭")); // 应该不通过验证，因为包含"吃饭"
        assertFalse(trie.isValid("我要吃饭啊")); // 应该不通过验证，因为包含"吃饭"
        
        // 但如果直接添加"吃饭啊"应该能检测到
        List<String> words2 = Arrays.asList("吃饭啊", "吃饭");
        SimpleTrie trie2 = new SimpleTrie(words2);
        assertFalse(trie2.isValid("我要吃饭啊"));
    }

    @Test
    void testRecursionEndCondition() {
        // 测试递归结束条件：到达文本末尾
        List<String> words = Arrays.asList("a");
        SimpleTrie trie = new SimpleTrie(words);
        
        assertFalse(trie.isValid("a")); // 单字符匹配，应该不通过验证
        List<String> result = trie.validate("a");
        assertEquals(1, result.size());
        assertTrue(result.contains("a"));
    }

    @Test
    void testRecursionEndAtTextEnd() {
        // 测试递归结束条件：到达文本末尾且未匹配到敏感词
        List<String> words = Arrays.asList("ab");
        SimpleTrie trie = new SimpleTrie(words);
        
        // 测试文本"a"只匹配了敏感词"ab"的第一个字符，但没有完整的匹配
        // 这会触发recursion方法中index == text.length()的条件，返回true
        assertTrue(trie.isValid("a"));
        
        // 测试文本"ac"第一个字符就不匹配
        assertTrue(trie.isValid("ac"));
    }

    @Test
    void testSpecialCharacters() {
        // 测试特殊字符
        List<String> words = Arrays.asList("特殊$符号", "换行\n符", "制表\t符");
        SimpleTrie trie = new SimpleTrie(words);
        
        assertFalse(trie.isValid("包含特殊$符号的文本"));
        assertFalse(trie.isValid("包含换行\n符的文本"));
        assertFalse(trie.isValid("包含制表\t符的文本"));
        
        List<String> result = trie.validate("特殊$符号和换行\n符和制表\t符");
        assertEquals(3, result.size());
        assertTrue(result.contains("特殊$符号"));
        assertTrue(result.contains("换行\n符"));
        assertTrue(result.contains("制表\t符"));
    }

    @Test
    void testUnicodeCharacters() {
        // 测试Unicode字符
        List<String> words = Arrays.asList("中文", "English", "数字123", "表情😀");
        SimpleTrie trie = new SimpleTrie(words);
        
        assertFalse(trie.isValid("包含中文的文本"));
        assertFalse(trie.isValid("Contains English words"));
        assertFalse(trie.isValid("包含数字123的内容"));
        assertFalse(trie.isValid("包含表情😀的文本"));
        
        List<String> result = trie.validate("混合中文English数字123和表情😀");
        assertEquals(4, result.size());
        assertTrue(result.contains("中文"));
        assertTrue(result.contains("English"));
        assertTrue(result.contains("数字123"));
        assertTrue(result.contains("表情😀"));
    }

    @Test
    void testValidateWithoutSensitiveWords() {
        // 测试没有敏感词的情况，覆盖validate方法中!ok为false的分支
        List<String> result = simpleTrie.validate("正常文本内容");
        assertTrue(result.isEmpty());
        
        // 测试部分匹配但不完整的敏感词情况
        List<String> words = Arrays.asList("abcd");
        SimpleTrie trie = new SimpleTrie(words);
        result = trie.validate("abc"); // 只匹配了部分，没有完整匹配
        assertTrue(result.isEmpty());
        
        // 测试在recursionWithResult中child==null的情况
        result = trie.validate("abe"); // "ab"匹配但'e'不匹配，触发child==null的分支
        assertTrue(result.isEmpty());
    }
}