# #region DictionaryEntryCRUD [C:3] [TYPE Class] [SEMANTICS dictionary, entries, crud]
# @BRIEF CRUD operations for DictionaryEntry records.
# @RELATION DEPENDS_ON -> [DictionaryEntry]
# @RELATION DEPENDS_ON -> [TerminologyDictionary]

from sqlalchemy import func
from sqlalchemy.orm import Session

from ...core.logger import belief_scope, logger
from ...models.translate import DictionaryEntry, TerminologyDictionary
from ._utils import _normalize_term
from .dictionary_validation import _validate_bcp47


class DictionaryEntryCRUD:
    """CRUD operations for dictionary entries."""

    # region add_entry [TYPE Function]
    # @PURPOSE: Add an entry to a dictionary with language-pair-aware uniqueness validation.
    @staticmethod
    def add_entry(
        db: Session, dict_id: str, source_term: str, target_term: str,
        context_notes: str | None = None,
        source_language: str = "und", target_language: str = "und",
    ) -> DictionaryEntry:
        with belief_scope("DictionaryEntryCRUD.add_entry"):
            _validate_bcp47(source_language, "source_language")
            _validate_bcp47(target_language, "target_language")

            normalized = _normalize_term(source_term)
            existing = (
                db.query(DictionaryEntry)
                .filter(
                    DictionaryEntry.dictionary_id == dict_id,
                    DictionaryEntry.source_term_normalized == normalized,
                    DictionaryEntry.source_language == source_language,
                    DictionaryEntry.target_language == target_language,
                )
                .first()
            )
            if existing:
                raise ValueError(
                    f"Duplicate entry: '{source_term}' (lang: {source_language}→{target_language}) "
                    f"already exists in this dictionary (id={existing.id}). "
                    "Use overwrite or keep_existing conflict mode."
                )

            logger.reason("Adding dictionary entry", {"dict_id": dict_id, "term": source_term})
            entry = DictionaryEntry(
                dictionary_id=dict_id,
                source_term=source_term.strip(),
                source_term_normalized=normalized,
                target_term=target_term.strip(),
                context_notes=context_notes.strip() if context_notes else None,
                source_language=source_language.strip(),
                target_language=target_language.strip(),
            )
            db.add(entry)
            db.commit()
            db.refresh(entry)
            logger.reflect("Entry added", {"entry_id": entry.id})
            return entry
    # endregion add_entry

    # region edit_entry [TYPE Function]
    # @PURPOSE: Edit an existing dictionary entry with language-pair-aware duplicate check.
    @staticmethod
    def edit_entry(
        db: Session, entry_id: str, source_term: str | None = None,
        target_term: str | None = None, context_notes: str | None = None,
        source_language: str | None = None, target_language: str | None = None,
    ) -> DictionaryEntry:
        with belief_scope("DictionaryEntryCRUD.edit_entry"):
            entry = db.query(DictionaryEntry).filter(DictionaryEntry.id == entry_id).first()
            if not entry:
                raise ValueError(f"Entry not found: {entry_id}")
            logger.reason("Editing dictionary entry", {"entry_id": entry_id})

            if source_language is not None:
                _validate_bcp47(source_language, "source_language")
                entry.source_language = source_language.strip()
            if target_language is not None:
                _validate_bcp47(target_language, "target_language")
                entry.target_language = target_language.strip()

            if source_term is not None:
                normalized = _normalize_term(source_term)
                existing = (
                    db.query(DictionaryEntry)
                    .filter(
                        DictionaryEntry.dictionary_id == entry.dictionary_id,
                        DictionaryEntry.source_term_normalized == normalized,
                        DictionaryEntry.source_language == entry.source_language,
                        DictionaryEntry.target_language == entry.target_language,
                        DictionaryEntry.id != entry_id,
                    )
                    .first()
                )
                if existing:
                    raise ValueError(f"Duplicate entry: '{source_term}' already exists in this dictionary (id={existing.id}).")
                entry.source_term = source_term.strip()
                entry.source_term_normalized = normalized
            if target_term is not None:
                entry.target_term = target_term.strip()
            if context_notes is not None:
                entry.context_notes = context_notes.strip() if context_notes else None
            db.commit()
            db.refresh(entry)
            logger.reflect("Entry updated", {"entry_id": entry.id})
            return entry
    # endregion edit_entry

    # region delete_entry [TYPE Function]
    # @PURPOSE: Delete a single dictionary entry.
    @staticmethod
    def delete_entry(db: Session, entry_id: str) -> None:
        with belief_scope("DictionaryEntryCRUD.delete_entry"):
            entry = db.query(DictionaryEntry).filter(DictionaryEntry.id == entry_id).first()
            if not entry:
                raise ValueError(f"Entry not found: {entry_id}")
            logger.reason("Deleting dictionary entry", {"entry_id": entry_id})
            db.delete(entry)
            db.commit()
            logger.reflect("Entry deleted", {"entry_id": entry_id})
    # endregion delete_entry

    # region clear_entries [TYPE Function]
    # @PURPOSE: Delete all entries for a dictionary.
    @staticmethod
    def clear_entries(db: Session, dict_id: str) -> int:
        with belief_scope("DictionaryEntryCRUD.clear_entries"):
            dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
            if not dictionary:
                raise ValueError(f"Dictionary not found: {dict_id}")
            logger.reason("Clearing all entries", {"dict_id": dict_id})
            deleted = db.query(DictionaryEntry).filter(DictionaryEntry.dictionary_id == dict_id).delete()
            db.commit()
            logger.reflect("Entries cleared", {"dict_id": dict_id, "count": deleted})
            return deleted
    # endregion clear_entries

    # region list_entries [TYPE Function]
    # @PURPOSE: List entries for a dictionary with pagination.
    @staticmethod
    def list_entries(
        db: Session, dict_id: str, page: int = 1, page_size: int = 50,
    ) -> tuple[list[DictionaryEntry], int]:
        total = (
            db.query(func.count(DictionaryEntry.id))
            .filter(DictionaryEntry.dictionary_id == dict_id)
            .scalar() or 0
        )
        entries = (
            db.query(DictionaryEntry)
            .filter(DictionaryEntry.dictionary_id == dict_id)
            .order_by(DictionaryEntry.source_term.asc())
            .offset((page - 1) * page_size)
            .limit(page_size)
            .all()
        )
        return entries, total
    # endregion list_entries

# #endregion DictionaryEntryCRUD
