# #region Test.DictionaryEntryCRUD [C:3] [TYPE Module] [SEMANTICS test,dictionary,entries,crud]
# @BRIEF Tests for dictionary_entries.py — DictionaryEntryCRUD.
# @RELATION BINDS_TO -> [DictionaryEntryCRUD]
# @TEST_EDGE: duplicate_entry -> ValueError
# @TEST_EDGE: entry_not_found -> ValueError
# @TEST_EDGE: invalid_regex -> ValueError

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

import pytest
from unittest.mock import MagicMock

from src.models.translate import DictionaryEntry, TerminologyDictionary
from src.plugins.translate.dictionary_entries import DictionaryEntryCRUD


class TestAddEntry:
    """DictionaryEntryCRUD.add_entry."""

    def test_add_basic(self, db_session):
        """Basic add creates entry."""
        dict_entry = TerminologyDictionary(id="dict-add-1", name="Test Dict", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        entry = DictionaryEntryCRUD.add_entry(
            db_session, "dict-add-1", "hello", "bonjour",
            source_language="en", target_language="fr",
        )
        assert entry.source_term == "hello"
        assert entry.target_term == "bonjour"
        assert entry.source_language == "en"
        assert entry.target_language == "fr"

    def test_add_with_context_notes(self, db_session):
        """Context notes are stripped."""
        dict_entry = TerminologyDictionary(id="dict-add-ctx", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        entry = DictionaryEntryCRUD.add_entry(
            db_session, "dict-add-ctx", "hello", "bonjour",
            context_notes="  formal greeting  ",
        )
        assert entry.context_notes == "formal greeting"

    def test_duplicate_raises(self, db_session):
        """Duplicate entry raises ValueError."""
        dict_entry = TerminologyDictionary(id="dict-add-dup", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        DictionaryEntryCRUD.add_entry(
            db_session, "dict-add-dup", "hello", "bonjour",
            source_language="en", target_language="fr",
        )

        with pytest.raises(ValueError, match="Duplicate"):
            DictionaryEntryCRUD.add_entry(
                db_session, "dict-add-dup", "hello", "salut",
                source_language="en", target_language="fr",
            )

    def test_invalid_source_language(self, db_session):
        """Invalid source_language raises ValueError."""
        dict_entry = TerminologyDictionary(id="dict-add-lang", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        with pytest.raises(ValueError, match="source_language"):
            DictionaryEntryCRUD.add_entry(
                db_session, "dict-add-lang", "hello", "bonjour",
                source_language="invalid!",
            )

    def test_invalid_regex_raises(self, db_session):
        """Invalid regex source_term raises ValueError."""
        dict_entry = TerminologyDictionary(id="dict-add-regex", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        with pytest.raises(ValueError, match="Invalid regex"):
            DictionaryEntryCRUD.add_entry(
                db_session, "dict-add-regex", r"[invalid", "bonjour",
                is_regex=True,
            )

    def test_valid_regex(self, db_session):
        """Valid regex is accepted."""
        dict_entry = TerminologyDictionary(id="dict-add-regex2", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        entry = DictionaryEntryCRUD.add_entry(
            db_session, "dict-add-regex2", r"\d+", "NUMBER",
            is_regex=True,
        )
        assert entry.is_regex is True

    def test_duplicate_different_language_passes(self, db_session):
        """Same source term with different language pair is OK."""
        dict_entry = TerminologyDictionary(id="dict-add-diff", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        DictionaryEntryCRUD.add_entry(
            db_session, "dict-add-diff", "hello", "bonjour",
            source_language="en", target_language="fr",
        )

        entry = DictionaryEntryCRUD.add_entry(
            db_session, "dict-add-diff", "hello", "hola",
            source_language="en", target_language="es",
        )
        assert entry.target_term == "hola"


class TestEditEntry:
    """DictionaryEntryCRUD.edit_entry."""

    def _setup(self, db_session):
        dict_entry = TerminologyDictionary(id="dict-edit-1", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        entry = DictionaryEntryCRUD.add_entry(
            db_session, "dict-edit-1", "hello", "bonjour",
            source_language="en", target_language="fr",
        )
        return entry

    def test_edit_target_term(self, db_session):
        """Edit target_term."""
        entry = self._setup(db_session)
        updated = DictionaryEntryCRUD.edit_entry(
            db_session, entry.id, target_term="salut"
        )
        assert updated.target_term == "salut"

    def test_edit_source_term(self, db_session):
        """Edit source_term with duplicate check."""
        entry = self._setup(db_session)
        updated = DictionaryEntryCRUD.edit_entry(
            db_session, entry.id, source_term="hi"
        )
        assert updated.source_term == "hi"

    def test_edit_languages(self, db_session):
        """Edit source_language and target_language."""
        entry = self._setup(db_session)
        updated = DictionaryEntryCRUD.edit_entry(
            db_session, entry.id,
            source_language="es", target_language="de",
        )
        assert updated.source_language == "es"
        assert updated.target_language == "de"

    def test_edit_not_found(self, db_session):
        """Non-existent entry raises ValueError."""
        with pytest.raises(ValueError, match="Entry not found"):
            DictionaryEntryCRUD.edit_entry(db_session, "nonexistent", source_term="x")

    def test_edit_context_notes(self, db_session):
        """Edit context_notes to None."""
        entry = self._setup(db_session)
        updated = DictionaryEntryCRUD.edit_entry(
            db_session, entry.id, context_notes=""
        )
        assert updated.context_notes is None

    def test_edit_duplicate_source_term_raises(self, db_session):
        """Changing source_term to an existing one raises."""
        entry1 = self._setup(db_session)
        entry2 = DictionaryEntryCRUD.add_entry(
            db_session, "dict-edit-1", "world", "monde",
            source_language="en", target_language="fr",
        )

        with pytest.raises(ValueError, match="Duplicate"):
            DictionaryEntryCRUD.edit_entry(
                db_session, entry2.id, source_term="hello"
            )

    def test_edit_is_regex(self, db_session):
        """Edit is_regex flag."""
        entry = self._setup(db_session)
        updated = DictionaryEntryCRUD.edit_entry(
            db_session, entry.id, is_regex=True
        )
        assert updated.is_regex is True

    def test_edit_regex_source_term_validation(self, db_session):
        """Setting source_term to invalid regex when entry is regex raises."""
        entry = self._setup(db_session)
        DictionaryEntryCRUD.edit_entry(db_session, entry.id, is_regex=True)

        with pytest.raises(ValueError, match="Invalid regex"):
            DictionaryEntryCRUD.edit_entry(
                db_session, entry.id, source_term=r"[invalid"
            )


class TestDeleteEntry:
    """DictionaryEntryCRUD.delete_entry."""

    def _setup(self, db_session):
        dict_entry = TerminologyDictionary(id="dict-del-1", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        entry = DictionaryEntryCRUD.add_entry(
            db_session, "dict-del-1", "hello", "bonjour",
        )
        return entry

    def test_delete(self, db_session):
        """Delete existing entry."""
        entry = self._setup(db_session)
        entry_id = entry.id
        DictionaryEntryCRUD.delete_entry(db_session, entry_id)
        assert db_session.query(DictionaryEntry).filter(DictionaryEntry.id == entry_id).first() is None

    def test_delete_not_found(self, db_session):
        """Delete non-existent entry raises ValueError."""
        with pytest.raises(ValueError, match="Entry not found"):
            DictionaryEntryCRUD.delete_entry(db_session, "nonexistent")


class TestClearEntries:
    """DictionaryEntryCRUD.clear_entries."""

    def test_clear(self, db_session):
        """Clear all entries for a dictionary."""
        dict_entry = TerminologyDictionary(id="dict-clear-1", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        DictionaryEntryCRUD.add_entry(db_session, "dict-clear-1", "hello", "bonjour")
        DictionaryEntryCRUD.add_entry(db_session, "dict-clear-1", "world", "monde")

        deleted = DictionaryEntryCRUD.clear_entries(db_session, "dict-clear-1")
        assert deleted == 2

    def test_clear_dictionary_not_found(self, db_session):
        """Clear non-existent dictionary raises ValueError."""
        with pytest.raises(ValueError, match="Dictionary not found"):
            DictionaryEntryCRUD.clear_entries(db_session, "nonexistent")


class TestListEntries:
    """DictionaryEntryCRUD.list_entries."""

    def test_list_pagination(self, db_session):
        """List with pagination."""
        dict_entry = TerminologyDictionary(id="dict-list-1", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        for i in range(5):
            DictionaryEntryCRUD.add_entry(
                db_session, "dict-list-1", f"term{i}", f"trans{i}",
            )

        entries, total = DictionaryEntryCRUD.list_entries(db_session, "dict-list-1", page=1, page_size=2)
        assert len(entries) == 2
        assert total == 5

    def test_list_empty(self, db_session):
        """Empty dictionary returns empty list."""
        dict_entry = TerminologyDictionary(id="dict-list-empty", name="Test", is_active=True)
        db_session.add(dict_entry)
        db_session.commit()

        entries, total = DictionaryEntryCRUD.list_entries(db_session, "dict-list-empty")
        assert entries == []
        assert total == 0
# #endregion Test.DictionaryEntryCRUD
