"""לולאת למידה — השוואת טיוטה לגרסה סופית וחילוץ לקחים.

שלב 7 באיפיון:
1. קליטת גרסה סופית (שדפנה חתמה)
2. השוואת טיוטה לסופית — זיהוי שינויים
3. חילוץ לקחים: ביטויים חדשים, דפוסים שהשתנו, שגיאות חוזרות
4. עדכון מודל הסגנון
"""

from __future__ import annotations

import logging
from uuid import UUID

from legal_mcp import config
from legal_mcp.config import parse_llm_json
from legal_mcp.services import db, claude_session

logger = logging.getLogger(__name__)


def compute_diff_stats(draft_text: str, final_text: str) -> dict:
    """חישוב סטטיסטיקות השוואה בין טיוטה לסופית."""
    draft_words = draft_text.split()
    final_words = final_text.split()

    draft_len = len(draft_words)
    final_len = len(final_words)

    # Simple word-level diff (not a full diff algorithm, but good enough for stats)
    draft_set = set(draft_words)
    final_set = set(final_words)

    common = draft_set & final_set
    added = final_set - draft_set
    removed = draft_set - final_set

    # Estimate change percentage
    if draft_len == 0:
        change_pct = 100.0
    else:
        change_pct = (len(added) + len(removed)) / max(draft_len, final_len) * 100

    return {
        "draft_words": draft_len,
        "final_words": final_len,
        "change_percent": round(change_pct, 1),
        "words_added": len(added),
        "words_removed": len(removed),
        "words_common": len(common),
    }


LESSONS_PROMPT = """אתה מנתח את הפער בין טיוטה (AI) לגרסה סופית שדפנה תמיר חתמה, כדי ללמוד **איך דפנה כותבת ומנתחת** — לא את ההלכה הספציפית.

## הבחנה קריטית (INV-LRN5 — טוהר-הקול):
לכל שינוי קבע `domain`:
- **style_method** — *איך* דפנה כותבת/חושבת: ניסוח, קצב, מבנה, תנועות-הנמקה, ביטויי-מעבר, טון, סדר-טיפול. **זה מה שלומדים** (ניתן להכללה לכל תיק).
- **substance** — תוכן ספציפי-לתיק: הלכה, עובדה, תקדים, מספר. **לא לומדים** (לא ניתן לגרור לתיק אחר).

## משימה:
1. זהה שינויים מהותיים (לא הקלדה/פורמט/מספור-אוטומטי).
2. לכל שינוי: `type` (expression_change / structure_change / content_addition / content_removal / tone_change / reasoning_move / error_fix) + `domain` (style_method / substance).
3. הסק לקח **מופשט** (על השיטה/הקול, לא על התוכן) — רק עבור style_method.

## פלט JSON:
{
  "changes": [
    {"type": "...", "domain": "style_method|substance", "block": "block-yod", "description": "...", "draft_text": "...", "final_text": "...", "lesson": "לקח מופשט (style_method בלבד)"}
  ],
  "new_expressions": ["ביטוי-מעבר/נוסחה חדשים (style_method בלבד — לא הלכות)"],
  "overall_assessment": "1-2 משפטים"
}
"""


async def analyze_changes(draft_text: str, final_text: str) -> dict:
    """ניתוח שינויים בין טיוטה לגרסה סופית עם Claude."""
    # Truncate for context window
    max_chars = 15000
    draft_sample = draft_text[:max_chars]
    final_sample = final_text[:max_chars]

    prompt = f"""{LESSONS_PROMPT}

--- טיוטה ---
{draft_sample}

--- גרסה סופית ---
{final_sample}
"""
    result = await claude_session.query_json(prompt, tools="")  # no tool_use → no error_max_turns
    if result is None:
        logger.warning("Failed to parse lessons response")
        return {"changes": [], "new_expressions": [], "overall_assessment": ""}
    return result


async def process_final_version(
    case_id: UUID,
    final_text: str,
) -> dict:
    """קליטת גרסה סופית, השוואה לטיוטה, חילוץ לקחים.

    Args:
        case_id: מזהה התיק
        final_text: טקסט הגרסה הסופית

    Returns:
        dict עם diff stats, changes, lessons
    """
    decision = await db.get_decision_by_case(case_id)
    if not decision:
        raise ValueError(f"No decision for case {case_id}")

    # Prefer the immutable snapshot captured at mark-final (T5/INV-LRN4); fall back
    # to the live blocks (which may have been edited after sign-off).
    pool = await db.get_pool()
    pair_id = None
    draft_text = ""
    async with pool.acquire() as conn:
        pair = await conn.fetchrow(
            """SELECT id, draft_text FROM draft_final_pairs
               WHERE case_id = $1 AND status = 'final_received'
               ORDER BY created_at DESC LIMIT 1""",
            case_id,
        )
        if pair:
            pair_id = pair["id"]
            draft_text = pair["draft_text"] or ""
        if not draft_text:
            rows = await conn.fetch(
                """SELECT content FROM decision_blocks
                   WHERE decision_id = $1 AND word_count > 0
                   ORDER BY block_index""",
                UUID(decision["id"]),
            )
            draft_text = "\n\n".join(r["content"] for r in rows if r["content"])

    if not draft_text:
        raise ValueError("No draft content to compare")

    # Compute stats (pure) + AI distillation (style/method vs substance)
    diff_stats = compute_diff_stats(draft_text, final_text)
    analysis = await analyze_changes(draft_text, final_text)

    # INV-LRN1: do NOT auto-commit learnings into writer-consumed channels.
    # The distillation is a PROPOSAL stored on the pair; the chair/curator approves
    # it (→ decision_lessons / appeal_type_rules, surfaced by T15) via the gate.
    # (Previously this auto-upserted every new_expression as a style_pattern —
    # that both bypassed the gate and contaminated style with substance. Removed.)
    #
    # create-or-update (INV-LRN4): normally mark-final already opened a
    # 'final_received' pair, so we just advance it. For a case whose final
    # pre-dates the mark-final snapshot mechanism (historical backfill) or a direct
    # ingest_final_version call, no pair exists — open one now from the live blocks
    # so the distillation is actually persisted instead of silently discarded.
    # Caveat: the captured draft is the CURRENT blocks (possibly edited after
    # sign-off), not a true mark-final snapshot.
    if pair_id is None:
        pair_id = await db.create_draft_final_pair(case_id, draft_text, "")
        logger.info(
            "process_final_version: no 'final_received' pair for case %s — opened one "
            "from live blocks (backfill path; draft may post-date sign-off)",
            case_id,
        )
    await db.update_draft_final_pair(
        UUID(str(pair_id)),
        final_text=final_text,
        diff_stats=diff_stats,
        analysis=analysis,
        status="analyzed",
    )

    # Update decision + case status
    await db.update_decision(UUID(decision["id"]), status="final")
    case = await db.get_case(case_id)
    if case:
        await db.update_case(case_id, status="final")

    return {
        "diff_stats": diff_stats,
        "analysis": analysis,
        "pair_id": str(pair_id) if pair_id else None,
        "lessons_count": len(analysis.get("changes", [])),
        "new_expressions": len(analysis.get("new_expressions", [])),
    }
