use super::*;

    use super::*;
    use crate::stemming::Stemmer;
    use crate::tokenize::WordTokenizer;

    #[test]
    fn test_pos_tagger_lexicon() {
        let tagger = PosTagger::new();

        // Test known words from lexicon
        let result = tagger.tag_word("running");
        assert_eq!(result.tag, PosTag::Verb);
        assert!(result.confidence > 0.8);

        let result = tagger.tag_word("house");
        assert_eq!(result.tag, PosTag::Noun);
        assert!(result.confidence > 0.8);

        let result = tagger.tag_word("beautiful");
        assert_eq!(result.tag, PosTag::Adjective);
        assert!(result.confidence > 0.8);

        let result = tagger.tag_word("quickly");
        assert_eq!(result.tag, PosTag::Adverb);
        assert!(result.confidence > 0.8);
    }

    #[test]
    fn test_pos_tagger_morphology() {
        let tagger = PosTagger::new();

        // Test morphological patterns for unknown words
        let result = tagger.tag_word("walking");
        assert_eq!(result.tag, PosTag::Verb); // -ing suffix

        let result = tagger.tag_word("happiness");
        assert_eq!(result.tag, PosTag::Noun); // -ness suffix

        let result = tagger.tag_word("colorful");
        assert_eq!(result.tag, PosTag::Adjective); // -ful suffix

        let result = tagger.tag_word("carefully");
        assert_eq!(result.tag, PosTag::Adverb); // -ly suffix
    }

    #[test]
    fn test_pos_tagger_sequence() {
        let tagger = PosTagger::new();
        let tokens = vec![
            "The".to_string(),
            "quick".to_string(),
            "brown".to_string(),
            "fox".to_string(),
            "jumps".to_string(),
        ];

        let result = tagger.tag_sequence(&tokens);

        assert_eq!(result.tokens.len(), 5);
        assert_eq!(result.tags.len(), 5);
        assert_eq!(result.confidences.len(), 5);

        // Check that we got reasonable tags
        assert_eq!(result.tags[0], PosTag::Other); // "The" (determiner)
        assert_eq!(result.tags[1], PosTag::Adjective); // "quick"
        assert_eq!(result.tags[2], PosTag::Adjective); // "brown"
        assert_eq!(result.tags[3], PosTag::Noun); // "fox"
        assert_eq!(result.tags[4], PosTag::Verb); // "jumps"
    }

    #[test]
    fn test_pos_taggertext() {
        let tagger = PosTagger::new();
        let tokenizer = WordTokenizer::default();

        let result = tagger.tagtext("The cat runs quickly", &tokenizer).expect("Operation failed");

        assert_eq!(result.tokens.len(), 4);
        assert_eq!(result.tags[0], PosTag::Other); // "The"
        assert_eq!(result.tags[1], PosTag::Noun); // "cat"
        assert_eq!(result.tags[2], PosTag::Verb); // "runs"
        assert_eq!(result.tags[3], PosTag::Adverb); // "quickly"
    }

    #[test]
    fn test_pos_tagger_custom_words() {
        let mut tagger = PosTagger::new();

        // Add custom word
        tagger.add_word("scirs", PosTag::Noun);

        let result = tagger.tag_word("scirs");
        assert_eq!(result.tag, PosTag::Noun);
        assert!(result.confidence > 0.8);

        // Remove word
        tagger.remove_word("scirs");
        let result = tagger.tag_word("scirs");
        assert_ne!(result.confidence, 0.9); // Should use morphological pattern now
    }

    #[test]
    fn test_pos_tagger_transition_probs() {
        let tagger = PosTagger::new();

        // Test transition probabilities
        let prob = tagger.get_transition_probability(&PosTag::Adjective, &PosTag::Noun);
        assert!(prob > 0.0);

        let prob = tagger.get_transition_probability(&PosTag::Noun, &PosTag::Verb);
        assert!(prob > 0.0);
    }

    #[test]
    fn test_pos_aware_lemmatizer() {
        let lemmatizer = PosAwareLemmatizer::new();

        // Test automatic POS detection and lemmatization
        assert_eq!(lemmatizer.lemmatize("running"), "run");
        assert_eq!(lemmatizer.lemmatize("cats"), "cat");
        assert_eq!(lemmatizer.lemmatize("better"), "good");
        assert_eq!(lemmatizer.lemmatize("quickly"), "quick");

        // Test explicit POS tagging
        assert_eq!(lemmatizer.lemmatize_with_pos("flies", PosTag::Verb), "fly");
        assert_eq!(lemmatizer.lemmatize_with_pos("flies", PosTag::Noun), "fly");

        // Test irregular forms
        assert_eq!(lemmatizer.lemmatize("went"), "go");
        assert_eq!(lemmatizer.lemmatize("children"), "child");
        assert_eq!(lemmatizer.lemmatize("feet"), "foot");
    }

    #[test]
    fn test_pos_aware_lemmatizertext() {
        let lemmatizer = PosAwareLemmatizer::new();
        let tokenizer = WordTokenizer::default();

        let result = lemmatizer
            .lemmatizetext("The cats are running quickly", &tokenizer)
            .expect("Operation failed");

        assert_eq!(result, vec!["the", "cat", "be", "run", "quick"]);
    }

    #[test]
    fn test_pos_aware_lemmatizer_stemmer_trait() {
        let lemmatizer = PosAwareLemmatizer::new();

        // Test Stemmer trait implementation
        assert_eq!(lemmatizer.stem("running").expect("Operation failed"), "run");
        assert_eq!(lemmatizer.stem("children").expect("Operation failed"), "child");

        // Test batch processing
        let words = vec!["running", "cats", "better", "quickly"];
        let expected = vec!["run", "cat", "good", "quick"];
        assert_eq!(lemmatizer.stem_batch(&words).expect("Operation failed"), expected);
    }

    #[test]
    fn test_pos_aware_lemmatizer_custom_additions() {
        let mut lemmatizer = PosAwareLemmatizer::new();

        // Add custom POS word
        lemmatizer.add_pos_word("tensorflow", PosTag::Noun);

        // Add custom lemma
        lemmatizer.add_lemma("tensorflow", "tf");

        assert_eq!(lemmatizer.lemmatize("tensorflow"), "tf");

        // Add custom exception
        lemmatizer.add_exception("pytorch", "torch");
        assert_eq!(lemmatizer.lemmatize("pytorch"), "torch");
    }

    #[test]
    fn test_pos_tagger_config() {
        let config = PosTaggerConfig {
            use_context: false,
            smoothing_factor: 0.01,
            use_morphology: true,
            use_capitalization: true,
        };

        let tagger = PosTagger::with_config(config);
        assert!(!tagger.use_context);
        assert_eq!(tagger.smoothing_factor, 0.01);
    }

    #[test]
    fn test_pos_tagging_capitalization() {
        let tagger = PosTagger::new();

        // Test proper noun detection
        let result = tagger.tag_word("John");
        assert_eq!(result.tag, PosTag::Noun); // Should be detected as proper noun

        let result = tagger.tag_word("USA");
        assert_eq!(result.tag, PosTag::Noun); // All caps should be noun
    }

    #[test]
    fn test_pos_tagger_confidence_scores() {
        let tagger = PosTagger::new();

        // Known word should have high confidence
        let result = tagger.tag_word("running");
        assert!(result.confidence > 0.8);

        // Unknown word should have lower confidence
        let result = tagger.tag_word("xyzunknown");
        assert!(result.confidence < 0.8);
    }

    #[test]
    fn test_pos_aware_lemmatizer_configurations() {
        let pos_config = PosTaggerConfig {
            use_context: false,
            smoothing_factor: 0.01,
            use_morphology: true,
            use_capitalization: true,
        };

        let lemma_config = crate::stemming::LemmatizerConfig {
            use_pos_tagging: true,
            default_pos: PosTag::Noun,
            apply_case_restoration: false,
            check_vowels: true,
        };

        let lemmatizer = PosAwareLemmatizer::with_configs(pos_config, lemma_config);

        // Test that it works with custom configs
        assert_eq!(lemmatizer.lemmatize("Running"), "run"); // Should not restore case
    }

    #[test]
    fn test_morphological_analyzer() {
        let analyzer = MorphologicalAnalyzer::new();

        // Test suffix analysis
        let predictions = analyzer.analyze("quickly");
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Adverb); // -ly suffix

        let predictions = analyzer.analyze("happiness");
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Noun); // -ness suffix

        let predictions = analyzer.analyze("beautiful");
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Adjective); // -ful suffix

        // Test prefix analysis
        let predictions = analyzer.analyze("unhappy");
        assert!(!predictions.is_empty());
        assert!(predictions.iter().any(|(tag, _)| *tag == PosTag::Adjective)); // un- prefix

        let predictions = analyzer.analyze("rebuild");
        assert!(!predictions.is_empty());
        assert!(predictions.iter().any(|(tag, _)| *tag == PosTag::Verb)); // re- prefix

        // Test word shape analysis
        let predictions = analyzer.analyze("JavaScript");
        assert!(!predictions.is_empty());
        assert!(predictions.iter().any(|(tag, _)| *tag == PosTag::Noun)); // CamelCase shape

        let predictions = analyzer.analyze("well-known");
        assert!(!predictions.is_empty());
        assert!(predictions.iter().any(|(tag, _)| *tag == PosTag::Adjective)); // hyphenated shape

        // Test prediction method
        let prediction = analyzer.predict_pos("running");
        assert!(prediction.is_some());
        let (tag, score) = prediction.expect("Operation failed");
        assert_eq!(tag, PosTag::Verb); // -ing suffix
        assert!(score > 0.0);
    }

    #[test]
    fn test_wordshape_detection() {
        let analyzer = MorphologicalAnalyzer::new();

        assert_eq!(analyzer.get_wordshape("Hello"), "Title");
        assert_eq!(analyzer.get_wordshape("WORLD"), "UPPER");
        assert_eq!(analyzer.get_wordshape("hello"), "lower");
        assert_eq!(analyzer.get_wordshape("CamelCase"), "CamelCase");
        assert_eq!(analyzer.get_wordshape("well-known"), "with-dash");
        assert_eq!(analyzer.get_wordshape("file_name"), "has_underscore");
        assert_eq!(analyzer.get_wordshape("Dr."), "has.period");
        assert_eq!(analyzer.get_wordshape("item123"), "123number");
        assert_eq!(analyzer.get_wordshape(""), "empty");
    }

    #[test]
    fn test_contextual_disambiguator() {
        let disambiguator = ContextualDisambiguator::new();

        // Test simple disambiguation
        let tokens = vec!["the".to_string(), "quick".to_string(), "fox".to_string()];
        let mut tags = vec![PosTag::Other, PosTag::Verb, PosTag::Noun]; // "quick" mistagged as verb
        let mut confidences = vec![0.9, 0.6, 0.9]; // low confidence for "quick"

        disambiguator.disambiguate(&tokens, &mut tags, &mut confidences);

        // "quick" should be disambiguated to adjective (determiner + ? + noun pattern)
        assert_eq!(tags[1], PosTag::Adjective);
        assert!(confidences[1] > 0.6); // confidence should increase

        // Test another pattern
        let tokens = vec!["he".to_string(), "run".to_string(), "fast".to_string()];
        let mut tags = vec![PosTag::Other, PosTag::Verb, PosTag::Adjective]; // "fast" might be adjective
        let mut confidences = vec![0.9, 0.8, 0.6];

        disambiguator.disambiguate(&tokens, &mut tags, &mut confidences);

        // "fast" after verb should be adverb
        assert_eq!(tags[2], PosTag::Adverb);
    }

    #[test]
    fn test_pattern_matching() {
        let disambiguator = ContextualDisambiguator::new();

        // Test exact pattern matching
        let pattern = (Some(PosTag::Other), PosTag::Adjective, Some(PosTag::Noun));
        assert!(disambiguator.matches_pattern(
            &pattern,
            Some(&PosTag::Other),
            &PosTag::Adjective,
            Some(&PosTag::Noun)
        ));

        // Test partial pattern matching (no left context required)
        let pattern = (None, PosTag::Adjective, Some(PosTag::Noun));
        assert!(disambiguator.matches_pattern(
            &pattern,
            None,
            &PosTag::Adjective,
            Some(&PosTag::Noun)
        ));

        // Test mismatch
        let pattern = (Some(PosTag::Verb), PosTag::Adjective, Some(PosTag::Noun));
        assert!(!disambiguator.matches_pattern(
            &pattern,
            Some(&PosTag::Other), // Wrong left context
            &PosTag::Adjective,
            Some(&PosTag::Noun)
        ));
    }

    #[test]
    fn test_morphological_edge_cases() {
        let analyzer = MorphologicalAnalyzer::new();

        // Test short words (should not match prefixes/suffixes)
        let predictions = analyzer.analyze("be");
        assert!(predictions.is_empty() || predictions[0].1 < 0.5); // Low confidence for short words

        // Test words that don't match any patterns
        let predictions = analyzer.analyze("xyz");
        assert!(predictions.is_empty() || predictions[0].1 < 0.5);

        // Test mixed patterns
        let predictions = analyzer.analyze("preprocessing"); // pre- prefix + -ing suffix
        assert!(!predictions.is_empty());
        // Should combine evidence from both prefix and suffix

        // Test capitalized technical terms
        let predictions = analyzer.analyze("PostgreSQL");
        assert!(!predictions.is_empty());
        assert!(predictions.iter().any(|(tag, _)| *tag == PosTag::Noun));
    }

    #[test]
    fn test_advanced_morphological_patterns() {
        let analyzer = MorphologicalAnalyzer::new();

        // Test compound patterns
        let predictions = analyzer.analyze("unhappiness"); // un- + -ness
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Noun); // -ness dominates

        let predictions = analyzer.analyze("reusable"); // re- + -able
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Adjective); // -able dominates

        // Test scientific/technical terms
        let predictions = analyzer.analyze("biodegradable");
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Adjective);

        let predictions = analyzer.analyze("programmer");
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Noun);

        // Test comparative/superlative
        let predictions = analyzer.analyze("fastest");
        assert!(!predictions.is_empty());
        assert_eq!(predictions[0].0, PosTag::Adjective);
    }
