# #region Test.OrchestratorLangStats [C:3] [TYPE Module] [SEMANTICS test, translate, language, stats, aggregation]
# @BRIEF Tests for orchestrator_lang_stats.py — update_language_stats.
# @RELATION BINDS_TO -> [update_language_stats]
# @TEST_CONTRACT: update_language_stats -> None | aggregates TranslationLanguage entries into stats
# @TEST_EDGE: empty_record_ids -> early return
# @TEST_EDGE: various_statuses -> correct counting

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "src"))

import os
os.environ.setdefault("SECRET_KEY", "test-secret-key-for-testing")
os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:")
os.environ.setdefault("AUTH_DATABASE_URL", "sqlite:///:memory:")

from unittest.mock import MagicMock, patch

import pytest

from src.plugins.translate.orchestrator_lang_stats import update_language_stats


class TestUpdateLanguageStats:
    """update_language_stats — aggregate language entries into stats objects."""

    def _make_lang_entry(self, code: str, status: str, translated_value: str | None = None):
        entry = MagicMock()
        entry.language_code = code
        entry.status = status
        entry.translated_value = translated_value
        return entry

    def test_no_records_returns_early(self):
        """No records for run_id -> early return."""
        db = MagicMock()
        db.query.return_value.filter.return_value.all.return_value = []
        event_log = MagicMock()
        stats_map = {}
        with patch("src.plugins.translate.orchestrator_lang_stats.logger") as mock_logger:
            update_language_stats(db, event_log, "run-1", stats_map)
        mock_logger.reason.assert_called_once()

    def test_single_language_all_translated(self):
        """Single language with all translated entries."""
        db = MagicMock()
        # Return one record
        db.query.return_value.filter.return_value.all.side_effect = [
            [MagicMock(id="rec-1")],  # TranslationRecords
            [self._make_lang_entry("ru", "translated", "привет")],  # TranslationLanguages
        ]
        ru_stat = MagicMock()
        stats_map = {"ru": ru_stat}

        update_language_stats(db, None, "run-1", stats_map)

        assert ru_stat.total_rows == 1
        assert ru_stat.translated_rows == 1
        assert ru_stat.failed_rows == 0
        assert ru_stat.skipped_rows == 0
        assert ru_stat.token_count >= 1
        assert ru_stat.estimated_cost >= 0
        db.flush.assert_called_once()

    def test_multiple_languages_multiple_statuses(self):
        """Multiple languages with various statuses counted correctly."""
        db = MagicMock()
        db.query.return_value.filter.return_value.all.side_effect = [
            [MagicMock(id="rec-1"), MagicMock(id="rec-2")],  # Records
            [  # Language entries
                self._make_lang_entry("ru", "translated", "привет"),
                self._make_lang_entry("ru", "failed", None),
                self._make_lang_entry("de", "translated", "hallo"),
                self._make_lang_entry("de", "skipped", None),
                self._make_lang_entry("de", "approved", "OK"),
                self._make_lang_entry("fr", "edited", "salut"),
            ],
        ]
        ru_stat = MagicMock()
        de_stat = MagicMock()
        fr_stat = MagicMock()
        stats_map = {"ru": ru_stat, "de": de_stat, "fr": fr_stat}

        update_language_stats(db, None, "run-1", stats_map)

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

        assert de_stat.total_rows == 3
        assert de_stat.translated_rows == 2  # translated + approved
        assert de_stat.failed_rows == 0
        assert de_stat.skipped_rows == 1

        assert fr_stat.total_rows == 1
        assert fr_stat.translated_rows == 1  # edited
        assert fr_stat.failed_rows == 0
        assert fr_stat.skipped_rows == 0

    def test_missing_language_in_stats_map(self):
        """Language in DB but not in stats_map -> ignored."""
        db = MagicMock()
        db.query.return_value.filter.return_value.all.side_effect = [
            [MagicMock(id="rec-1")],
            [self._make_lang_entry("ru", "translated", "привет")],
        ]
        ru_stat = MagicMock()
        stats_map = {"ru": ru_stat}

        update_language_stats(db, None, "run-1", stats_map)
        assert ru_stat.total_rows == 1

    def test_language_not_in_agg_uses_defaults(self):
        """Language in stats_map but no entries -> all zeros."""
        db = MagicMock()
        db.query.return_value.filter.return_value.all.side_effect = [
            [MagicMock(id="rec-1")],
            [self._make_lang_entry("ru", "translated", "привет")],
        ]
        ru_stat = MagicMock()
        de_stat = MagicMock()
        stats_map = {"ru": ru_stat, "de": de_stat}

        update_language_stats(db, None, "run-1", stats_map)
        assert ru_stat.total_rows == 1
        assert de_stat.total_rows == 0
        assert de_stat.translated_rows == 0
        assert de_stat.failed_rows == 0
        assert de_stat.skipped_rows == 0

    def test_token_count_distribution(self):
        """Token count is distributed equally among languages."""
        db = MagicMock()
        db.query.return_value.filter.return_value.all.side_effect = [
            [MagicMock(id="rec-1")],
            [self._make_lang_entry("ru", "translated", "hello world")],
        ]
        ru_stat = MagicMock()
        de_stat = MagicMock()
        stats_map = {"ru": ru_stat, "de": de_stat}

        update_language_stats(db, None, "run-1", stats_map)
        # total_chars = 11, total_tokens = 11 // 4 = 2, each gets 2 // 2 = 1
        assert ru_stat.token_count == 1
        assert de_stat.token_count == 1

    def test_zero_token_falls_back_to_one(self):
        """When no text translated, total_tokens defaults to 1."""
        db = MagicMock()
        db.query.return_value.filter.return_value.all.side_effect = [
            [MagicMock(id="rec-1")],
            [self._make_lang_entry("ru", "failed", None)],
        ]
        ru_stat = MagicMock()
        stats_map = {"ru": ru_stat}

        update_language_stats(db, None, "run-1", stats_map)
        assert ru_stat.token_count >= 1
# #endregion Test.OrchestratorLangStats
