"""Correction detection — detect when users correct memory facts.

Compares old vs new fact values for same attribute_key to identify corrections.
"""

from __future__ import annotations

import logging
from dataclasses import dataclass, field
from typing import Any

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from arandu.models import MemoryFact

logger = logging.getLogger(__name__)

__all__ = [
    "CorrectionResult",
    "detect_and_record_corrections",
    "is_user_correction",
]


@dataclass
class CorrectionResult:
    """Result of correction detection.

    Attributes:
        corrections_detected: Number of corrections found.
        corrected_keys: Attribute keys that were corrected.
        facts_corrected_ids: IDs of old facts that were corrected.
    """

    corrections_detected: int = 0
    corrected_keys: list[str] = field(default_factory=list)
    facts_corrected_ids: list[str] = field(default_factory=list)


def _values_equal(a: Any, b: Any) -> bool:
    """Compare two fact values for equality (dict or primitive)."""
    if a is None and b is None:
        return True
    if a is None or b is None:
        return False
    return bool(a == b)


def is_user_correction(old_fact: object, new_fact: object) -> bool:
    """Check if new_fact corrects old_fact (same key, different value).

    Args:
        old_fact: The existing fact being superseded.
        new_fact: The new fact replacing it.

    Returns:
        True if this is a user correction.
    """
    old_key = getattr(old_fact, "attribute_key", None)
    new_key = getattr(new_fact, "attribute_key", None)
    if old_key != new_key:
        return False
    return not _values_equal(
        getattr(old_fact, "value_json", None),
        getattr(new_fact, "value_json", None),
    )


async def detect_and_record_corrections(
    session: AsyncSession,
    user_id: str,
    saved_facts: list[Any],
) -> CorrectionResult:
    """Detect supersedes with value changes and increment correction count.

    For each saved fact that supersedes another, checks if the value changed.
    If so, increments ``user_correction_count`` on the old fact.

    Args:
        session: Database session.
        user_id: User identifier.
        saved_facts: List of newly saved MemoryFact objects.

    Returns:
        CorrectionResult with detection stats.
    """
    result = CorrectionResult()
    for new_fact in saved_facts:
        supersedes_id = getattr(new_fact, "supersedes_fact_id", None)
        if supersedes_id is None:
            continue
        stmt = select(MemoryFact).where(
            MemoryFact.id == supersedes_id,
            MemoryFact.user_id == user_id,
        )
        row = await session.execute(stmt)
        old_fact = row.scalar_one_or_none()
        if old_fact is None:
            continue
        if not is_user_correction(old_fact, new_fact):
            continue
        old_fact.user_correction_count = (getattr(old_fact, "user_correction_count", 0) or 0) + 1
        session.add(old_fact)
        result.corrections_detected += 1
        result.corrected_keys.append(old_fact.attribute_key)  # type: ignore[arg-type]
        result.facts_corrected_ids.append(str(old_fact.id))
    await session.flush()
    return result
