# #region DictionaryCRUD [C:3] [TYPE Class] [SEMANTICS dictionary, crud, terminology]
# @BRIEF CRUD operations for TerminologyDictionary records.
# @RELATION DEPENDS_ON -> [TerminologyDictionary]
# @RELATION DEPENDS_ON -> [TranslationJob]
# @RELATION DEPENDS_ON -> [TranslationJobDictionary]

from sqlalchemy import func
from sqlalchemy.orm import Session

from ...core.logger import belief_scope, logger
from ...models.translate import (
    DictionaryEntry,
    TerminologyDictionary,
    TranslationJob,
    TranslationJobDictionary,
)


class DictionaryCRUD:
    """CRUD operations for terminology dictionaries."""

    # region create_dictionary [TYPE Function]
    # @PURPOSE: Create a new terminology dictionary.
    @staticmethod
    def create_dictionary(
        db: Session, name: str,
        source_dialect: str = "", target_dialect: str = "",
        created_by: str | None = None, description: str | None = None,
        is_active: bool = True,
    ) -> TerminologyDictionary:
        with belief_scope("DictionaryCRUD.create_dictionary"):
            logger.reason("Creating dictionary", {"name": name, "source": source_dialect, "target": target_dialect})
            dictionary = TerminologyDictionary(
                name=name, description=description,
                source_dialect=source_dialect or "", target_dialect=target_dialect or "",
                is_active=is_active, created_by=created_by,
            )
            db.add(dictionary)
            db.commit()
            db.refresh(dictionary)
            logger.reflect("Dictionary created", {"id": dictionary.id})
            return dictionary
    # endregion create_dictionary

    # region update_dictionary [TYPE Function]
    # @PURPOSE: Update an existing terminology dictionary.
    @staticmethod
    def update_dictionary(
        db: Session, dict_id: str, name: str | None = None,
        description: str | None = None, source_dialect: str | None = None,
        target_dialect: str | None = None, is_active: bool | None = None,
    ) -> TerminologyDictionary:
        with belief_scope("DictionaryCRUD.update_dictionary"):
            dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
            if not dictionary:
                raise ValueError(f"Dictionary not found: {dict_id}")
            logger.reason("Updating dictionary", {"id": dict_id})
            if name is not None:
                dictionary.name = name
            if description is not None:
                dictionary.description = description
            if source_dialect is not None:
                dictionary.source_dialect = source_dialect
            if target_dialect is not None:
                dictionary.target_dialect = target_dialect
            if is_active is not None:
                dictionary.is_active = is_active
            db.commit()
            db.refresh(dictionary)
            logger.reflect("Dictionary updated", {"id": dictionary.id})
            return dictionary
    # endregion update_dictionary

    # region delete_dictionary [TYPE Function]
    # @PURPOSE: Delete a dictionary, blocked if attached to active/scheduled jobs.
    @staticmethod
    def delete_dictionary(db: Session, dict_id: str) -> None:
        with belief_scope("DictionaryCRUD.delete_dictionary"):
            dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
            if not dictionary:
                raise ValueError(f"Dictionary not found: {dict_id}")

            blocked_statuses = ["ACTIVE", "READY", "RUNNING", "SCHEDULED"]
            attached_jobs = (
                db.query(TranslationJobDictionary)
                .filter(
                    TranslationJobDictionary.dictionary_id == dict_id,
                    TranslationJobDictionary.job_id.in_(
                        db.query(TranslationJob.id).filter(TranslationJob.status.in_(blocked_statuses))
                    ),
                )
                .count()
            )
            if attached_jobs > 0:
                logger.explore("Delete blocked: dictionary attached to active jobs", {"dict_id": dict_id, "jobs": attached_jobs})
                raise ValueError(
                    f"Cannot delete dictionary attached to {attached_jobs} active/scheduled job(s). "
                    "Remove dictionary associations from jobs first."
                )

            logger.reason("Deleting dictionary", {"id": dict_id})
            db.query(DictionaryEntry).filter(DictionaryEntry.dictionary_id == dict_id).delete()
            db.query(TranslationJobDictionary).filter(TranslationJobDictionary.dictionary_id == dict_id).delete()
            db.delete(dictionary)
            db.commit()
            logger.reflect("Dictionary deleted", {"id": dict_id})
    # endregion delete_dictionary

    # region get_dictionary [TYPE Function]
    # @PURPOSE: Get a single dictionary by ID.
    @staticmethod
    def get_dictionary(db: Session, dict_id: str) -> TerminologyDictionary:
        dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
        if not dictionary:
            raise ValueError(f"Dictionary not found: {dict_id}")
        return dictionary
    # endregion get_dictionary

    # region list_dictionaries [TYPE Function]
    # @PURPOSE: List dictionaries with pagination.
    @staticmethod
    def list_dictionaries(
        db: Session, page: int = 1, page_size: int = 20,
    ) -> tuple[list[TerminologyDictionary], int]:
        total = db.query(func.count(TerminologyDictionary.id)).scalar() or 0
        dictionaries = (
            db.query(TerminologyDictionary)
            .order_by(TerminologyDictionary.created_at.desc())
            .offset((page - 1) * page_size)
            .limit(page_size)
            .all()
        )
        return dictionaries, total
    # endregion list_dictionaries

# #endregion DictionaryCRUD
