# #region TestLangStats [C:2] [TYPE Module] [SEMANTICS test,translate,language,stats]
# @BRIEF Tests for orchestrator_lang_stats.update_language_stats — aggregation of per-language statistics.
# @RELATION BINDS_TO -> [update_language_stats]
import uuid
from unittest.mock import MagicMock

from src.models.translate import TranslationRecord, TranslationLanguage, TranslationRunLanguageStats
from src.plugins.translate.orchestrator_lang_stats import update_language_stats


# #region make_lang_entry [C:1] [TYPE Function]
def make_lang(code: str, status: str = "translated", value: str = "hello") -> TranslationLanguage:
    le = MagicMock(spec=TranslationLanguage)
    le.language_code = code
    le.status = status
    le.translated_value = value
    return le


def make_record(run_id: str) -> TranslationRecord:
    rec = MagicMock(spec=TranslationRecord)
    rec.id = str(uuid.uuid4())
    rec.run_id = run_id
    return rec
# #endregion make_lang_entry


# #region TestLangStatsAggregation [C:2] [TYPE Class]
class TestLangStatsAggregation:
    """Verify update_language_stats aggregates correctly."""

    def test_single_language_all_translated(self):
        db = MagicMock()
        run_id = "run-1"
        ru_stat = MagicMock(spec=TranslationRunLanguageStats)

        records = [make_record(run_id)]
        db.query.return_value.filter.return_value.all.side_effect = [
            records,
            [make_lang("ru", "translated", "Привет")],
        ]

        update_language_stats(db, None, run_id, {"ru": ru_stat})

        assert ru_stat.total_rows == 1
        assert ru_stat.translated_rows == 1
        assert ru_stat.failed_rows == 0
        assert ru_stat.skipped_rows == 0

    def test_mixed_statuses(self):
        db = MagicMock()
        run_id = "run-2"
        en_stat = MagicMock(spec=TranslationRunLanguageStats)

        records = [make_record(run_id)]
        langs = [
            make_lang("en", "translated", "Hello"),
            make_lang("en", "failed", ""),
            make_lang("en", "skipped", ""),
        ]
        db.query.return_value.filter.return_value.all.side_effect = [
            records,
            langs,
        ]

        update_language_stats(db, None, run_id, {"en": en_stat})

        assert en_stat.total_rows == 3
        assert en_stat.translated_rows == 1
        assert en_stat.failed_rows == 1
        assert en_stat.skipped_rows == 1

    def test_multiple_languages(self):
        db = MagicMock()
        run_id = "run-3"
        ru_stat = MagicMock(spec=TranslationRunLanguageStats)
        en_stat = MagicMock(spec=TranslationRunLanguageStats)

        records = [make_record(run_id), make_record(run_id)]
        langs = [
            make_lang("ru", "translated", "Привет"),
            make_lang("en", "translated", "Hello"),
        ]
        db.query.return_value.filter.return_value.all.side_effect = [
            records,
            langs,
        ]

        update_language_stats(db, None, run_id, {"ru": ru_stat, "en": en_stat})

        assert ru_stat.total_rows == 1
        assert ru_stat.translated_rows == 1
        assert en_stat.total_rows == 1
        assert en_stat.translated_rows == 1

    def test_empty_language_stats_map(self):
        db = MagicMock()
        run_id = "run-4"
        records = [make_record(run_id)]
        db.query.return_value.filter.return_value.all.side_effect = [
            records,
            [make_lang("ru", "translated")],
        ]

        # Should not raise even with empty map
        update_language_stats(db, None, run_id, {})
        # No assertions needed — just verifying no exception

    def test_no_records_returns_early(self):
        db = MagicMock()
        run_id = "run-5"
        db.query.return_value.filter.return_value.all.return_value = []

        update_language_stats(db, None, run_id, {"ru": MagicMock()})
        # Should return early without querying languages

    def test_approved_and_edited_count_as_translated(self):
        db = MagicMock()
        run_id = "run-6"
        de_stat = MagicMock(spec=TranslationRunLanguageStats)

        records = [make_record(run_id)]
        langs = [
            make_lang("de", "approved", "Hallo"),
            make_lang("de", "edited", "Guten Tag"),
            make_lang("de", "translated", "Tschüss"),
        ]
        db.query.return_value.filter.return_value.all.side_effect = [
            records,
            langs,
        ]

        update_language_stats(db, None, run_id, {"de": de_stat})

        assert de_stat.translated_rows == 3

    def test_token_and_cost_estimation(self):
        db = MagicMock()
        run_id = "run-7"
        en_stat = MagicMock(spec=TranslationRunLanguageStats)

        records = [make_record(run_id)]
        langs = [make_lang("en", "translated", "Hello World")]
        db.query.return_value.filter.return_value.all.side_effect = [
            records,
            langs,
        ]

        update_language_stats(db, None, run_id, {"en": en_stat})

        assert en_stat.token_count > 0
        assert en_stat.estimated_cost >= 0

    def test_empty_translated_value_no_crash(self):
        db = MagicMock()
        run_id = "run-8"
        ru_stat = MagicMock(spec=TranslationRunLanguageStats)

        records = [make_record(run_id)]
        langs = [make_lang("ru", "translated", None)]
        db.query.return_value.filter.return_value.all.side_effect = [
            records,
            langs,
        ]

        update_language_stats(db, None, run_id, {"ru": ru_stat})
        assert ru_stat.total_rows == 1
# #endregion TestLangStatsAggregation
