# #region DictionaryCorrectionService [C:3] [TYPE Class] [SEMANTICS dictionary, correction, bulk]
# @BRIEF Submit term corrections and bulk corrections to dictionaries with conflict detection.
# @RELATION DEPENDS_ON -> [DictionaryEntry]
# @RELATION DEPENDS_ON -> [TerminologyDictionary]

from typing import Any

from sqlalchemy import or_
from sqlalchemy.orm import Session

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


class DictionaryCorrectionService:
    """Submit term corrections to dictionaries with conflict detection and bulk support."""

    # region submit_correction [TYPE Function]
    # @PURPOSE: Submit a term correction from a run result.
    @staticmethod
    def submit_correction(
        db: Session,
        dict_id: str,
        source_term: str,
        incorrect_target_term: str,
        corrected_target_term: str,
        origin_run_id: str | None = None,
        origin_row_key: str | None = None,
        origin_user_id: str | None = None,
        on_conflict: str = "overwrite",
        context_data: dict[str, Any] | None = None,
        usage_notes: str | None = None,
        keep_context: bool = True,
    ) -> dict[str, Any]:
        with belief_scope("DictionaryCorrectionService.submit_correction"):
            dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
            if not dictionary:
                raise ValueError(f"Dictionary '{dict_id}' not found")

            effective_context = context_data
            effective_context_source = "auto"
            if not keep_context:
                effective_context = None
                effective_context_source = "manual"

            normalized = _normalize_term(source_term)
            entry_src_lang = dictionary.source_dialect or "und"
            entry_tgt_lang = dictionary.target_dialect or "und"

            existing = (
                db.query(DictionaryEntry)
                .filter(
                    DictionaryEntry.dictionary_id == dict_id,
                    DictionaryEntry.source_term_normalized == normalized,
                    or_(
                        (DictionaryEntry.source_language == entry_src_lang) & (DictionaryEntry.target_language == entry_tgt_lang),
                        (DictionaryEntry.source_language == "und") & (DictionaryEntry.target_language == "und"),
                    ),
                )
                .first()
            )

            result: dict[str, Any] = {"source_term": source_term, "target_term": corrected_target_term, "action": "created", "entry_id": None, "conflict": None, "message": None}

            if existing:
                if on_conflict == "keep_existing":
                    result["action"] = "conflict_detected"
                    result["conflict"] = {"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target_term, "action": "keep_existing"}
                    result["message"] = f"Existing entry kept: '{existing.target_term}'"
                    return result
                elif on_conflict == "overwrite":
                    existing.target_term = corrected_target_term.strip()
                    if origin_run_id:
                        existing.origin_run_id = origin_run_id
                    if origin_row_key:
                        existing.origin_row_key = origin_row_key
                    if origin_user_id:
                        existing.origin_user_id = origin_user_id
                    if context_data is not None or not keep_context:
                        existing.context_data = effective_context
                        existing.has_context = bool(effective_context)
                        existing.context_source = effective_context_source
                    if usage_notes is not None:
                        existing.usage_notes = usage_notes
                    db.flush()
                    result["action"] = "updated"
                    result["entry_id"] = existing.id
                    result["message"] = f"Entry updated from '{existing.target_term}' to '{corrected_target_term}'"
                else:
                    result["action"] = "skipped"
                    result["conflict"] = {"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target_term, "action": "cancel"}
                    result["message"] = "Correction cancelled by conflict mode"
                    return result
            else:
                entry = DictionaryEntry(
                    dictionary_id=dict_id, source_term=source_term.strip(),
                    source_term_normalized=normalized, target_term=corrected_target_term.strip(),
                    source_language=entry_src_lang, target_language=entry_tgt_lang,
                    context_data=effective_context, usage_notes=usage_notes,
                    has_context=bool(effective_context), context_source=effective_context_source if effective_context else None,
                    origin_run_id=origin_run_id, origin_row_key=origin_row_key, origin_user_id=origin_user_id,
                )
                db.add(entry)
                db.flush()
                result["entry_id"] = entry.id
                result["message"] = f"Entry created for '{source_term}' -> '{corrected_target_term}'"

            db.commit()
            logger.reflect("Correction processed", result)
            return result
    # endregion submit_correction

    # region submit_bulk_corrections [TYPE Function]
    # @PURPOSE: Submit multiple term corrections atomically.
    @staticmethod
    def submit_bulk_corrections(
        db: Session,
        dict_id: str,
        corrections: list[dict[str, Any]],
        origin_user_id: str | None = None,
    ) -> dict[str, Any]:
        with belief_scope("DictionaryCorrectionService.submit_bulk_corrections"):
            dictionary = db.query(TerminologyDictionary).filter(TerminologyDictionary.id == dict_id).first()
            if not dictionary:
                raise ValueError(f"Dictionary '{dict_id}' not found")

            results: list[dict[str, Any]] = []
            conflicts: list[dict[str, Any]] = []
            all_ok = True

            for corr in corrections:
                source_term = corr.get("source_term", "").strip()
                corrected_target = corr.get("corrected_target_term", "").strip()

                if not source_term or not corrected_target:
                    results.append({"source_term": source_term, "action": "error", "message": "source_term and corrected_target_term are required"})
                    all_ok = False
                    continue

                normalized = _normalize_term(source_term)
                bulk_src_lang = dictionary.source_dialect or "und"
                bulk_tgt_lang = dictionary.target_dialect or "und"

                existing = (
                    db.query(DictionaryEntry)
                    .filter(
                        DictionaryEntry.dictionary_id == dict_id,
                        DictionaryEntry.source_term_normalized == normalized,
                        or_(
                            (DictionaryEntry.source_language == bulk_src_lang) & (DictionaryEntry.target_language == bulk_tgt_lang),
                            (DictionaryEntry.source_language == "und") & (DictionaryEntry.target_language == "und"),
                        ),
                    )
                    .first()
                )

                if existing:
                    on_conflict = corr.get("on_conflict", "overwrite")
                    if on_conflict == "keep_existing":
                        conflicts.append({"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target, "action": "keep_existing"})
                        results.append({"source_term": source_term, "action": "conflict_detected", "message": f"Existing entry kept: '{existing.target_term}'"})
                        continue
                    elif on_conflict == "overwrite":
                        existing.target_term = corrected_target
                        existing.origin_user_id = origin_user_id
                        results.append({"source_term": source_term, "action": "updated", "entry_id": existing.id, "message": f"Updated to '{corrected_target}'"})
                    else:
                        conflicts.append({"source_term": source_term, "existing_target_term": existing.target_term, "submitted_target_term": corrected_target, "action": "cancel"})
                        results.append({"source_term": source_term, "action": "skipped", "message": "Cancelled by conflict mode"})
                else:
                    entry = DictionaryEntry(
                        dictionary_id=dict_id, source_term=source_term, source_term_normalized=normalized,
                        target_term=corrected_target, source_language=bulk_src_lang, target_language=bulk_tgt_lang,
                        origin_run_id=corr.get("origin_run_id"), origin_row_key=corr.get("origin_row_key"),
                        origin_user_id=origin_user_id,
                    )
                    db.add(entry)
                    results.append({"source_term": source_term, "action": "created", "message": f"Entry created for '{source_term}' -> '{corrected_target}'"})

            if conflicts and not all_ok:
                db.rollback()
                return {"status": "conflicts", "results": results, "conflicts": conflicts, "message": "Conflicts detected. Resolve before retrying."}

            db.commit()
            return {
                "status": "completed", "results": results, "conflicts": conflicts,
                "total": len(corrections), "applied": sum(1 for r in results if r["action"] in ("created", "updated")),
            }
    # endregion submit_bulk_corrections

# #endregion DictionaryCorrectionService
