"""MCP tools for the planning-schemes registry (טבלת plans, V38).

Extract/get-symmetry per X9: `extract_plans` is the expensive LLM extraction;
`plan_get`/`plan_search`/`plan_list` are cheap reads. `plan_upsert` is the manual
chair-curated write, `plan_review` is the human approval gate (INV-DM5/G10). Every
tool returns the SSoT JSON envelope (ok/err) — GAP-48.
"""

from __future__ import annotations

from uuid import UUID

from legal_mcp.services import db
from legal_mcp.tools.envelope import err, ok

_VALID_STATUS = ("pending_review", "approved", "rejected")


async def extract_plans(case_number: str) -> str:
    """חילוץ תכניות ותוקפן מכל מסמכי התיק אל מרשם-התכניות (נכנסות pending_review).

    ה-extract היקר (קריאת-LLM, לא-דטרמיניסטי) שמזין את המרשם. הרשומות ממתינות
    לאישור-יו"ר (plan_review) לפני שישמשו בכתיבת בלוק ט.

    Args:
        case_number: מספר תיק הערר
    """
    from legal_mcp.services import plans_extractor

    case = await db.get_case_by_number(case_number)
    if not case:
        return err(f"תיק {case_number} לא נמצא.")
    try:
        result = await plans_extractor.extract_plans_for_case(UUID(case["id"]))
        return ok(result)
    except Exception as e:  # noqa: BLE001 — surface, don't swallow
        return err(str(e))


async def plan_fetch(plan_number: str) -> str:
    """משיכת זהות+תוקף של תב"ע מ-מנהל-התכנון (mavat) — מועמד-לאישור, לא כתיבה.

    מחזיר את שדות-התכנית כפי שנמשכו (display_name/plan_type/purpose/gazette_date/
    yalkut_number/source_url). כל ערך נושא source_url (INV-AH); שדה שהמקור אינו
    חושף חוזר ריק — לא מומצא. אינו כותב למרשם: הקורא (טופס-היו"ר / plan_upsert)
    מחליט; הרשומה תמיד עוברת שער-יו"ר (review_status) לפני ציטוט בבלוק ט.

    Args:
        plan_number: מספר-התכנית למשיכה (למשל "101-1031020", "מי/820")
    """
    from legal_mcp.services import plans_fetch

    try:
        plan = await plans_fetch.fetch_plan(plan_number)
        return ok(plan)
    except plans_fetch.PlanFetchUnavailable as e:
        return err(f"שירות-המשיכה אינו זמין: {e}")
    except Exception as e:  # noqa: BLE001 — surface, don't swallow
        return err(str(e))


async def plan_get(plan_number: str) -> str:
    """קריאת תכנית מהמרשם לפי מספר (מנורמל; נופל ל-alias). ה-get הזול."""
    try:
        plan = await db.get_plan_by_number(plan_number)
    except Exception as e:  # noqa: BLE001
        return err(str(e))
    if not plan:
        return err(f"תכנית '{plan_number}' לא נמצאה במרשם.")
    return ok(plan)


async def plan_search(query: str, limit: int = 20) -> str:
    """חיפוש fuzzy במרשם לפי מספר/שם/ייעוד (ILIKE + tsvector)."""
    try:
        results = await db.search_plans(query, limit)
        return ok({"query": query, "count": len(results), "results": results})
    except Exception as e:  # noqa: BLE001
        return err(str(e))


async def plan_list(review_status: str = "", limit: int = 500) -> str:
    """רשימת תכניות במרשם, אופציונלית מסוננת לפי review_status (תור-אישור)."""
    if review_status and review_status not in _VALID_STATUS:
        return err("review_status חייב להיות אחד מ: pending_review / approved / rejected")
    try:
        plans = await db.list_plans(review_status, limit)
        return ok({
            "count": len(plans),
            "review_status": review_status or "all",
            "plans": plans,
        })
    except Exception as e:  # noqa: BLE001
        return err(str(e))


async def plan_upsert(
    plan_number: str,
    display_name: str = "",
    plan_type: str = "",
    gazette_date: str = "",
    yalkut_number: str = "",
    purpose: str = "",
    review_status: str = "approved",
    aliases: str = "",
) -> str:
    """כתיבה/עריכה ידנית מבוקרת של תכנית במרשם.

    קלט-יו"ר ידני — ברירת-המחדל review_status='approved' (היו"ר היא הסמכות). מנרמל את
    plan_number בכתיבה (G1) ו-upsert idempotent (G3). אם התכנית כבר מאושרת ותוקף-חדש
    סותר — הנתון נרשם ב-discrepancies ולא דורס (G10/§6).

    Args:
        plan_number: מזהה-התכנית (יומר לצורה קנונית) — למשל "מי/820", "תמ\\"א 38"
        display_name: שם-תצוגה כולל "תכנית" (למשל "תכנית מי/820")
        plan_type: ארצית/מחוזית/מקומית/מפורטת/כוללנית (אופציונלי)
        gazette_date: תאריך פרסום למתן תוקף ברשומות, ISO YYYY-MM-DD (אופציונלי)
        yalkut_number: מס' ילקוט הפרסומים / י"פ (אופציונלי)
        purpose: משפט-ייעוד אחד (אופציונלי)
        review_status: pending_review/approved/rejected (ברירת-מחדל approved)
        aliases: צורות חלופיות מופרדות בפסיק (אופציונלי)
    """
    if review_status not in _VALID_STATUS:
        return err("review_status חייב להיות אחד מ: pending_review / approved / rejected")
    alias_list = [a.strip() for a in aliases.split(",") if a.strip()] if aliases else []
    try:
        plan = await db.upsert_plan(
            plan_number=plan_number,
            display_name=display_name,
            aliases=alias_list,
            plan_type=plan_type,
            gazette_date=gazette_date or None,
            yalkut_number=yalkut_number,
            purpose=purpose,
            review_status=review_status,
            model_used="chair_manual",
        )
        return ok(plan)
    except ValueError as e:
        return err(str(e))
    except Exception as e:  # noqa: BLE001
        return err(str(e))


async def plan_review(plan_id: str, status: str) -> str:
    """שער-היו"ר (G10): אישור / דחייה / איפוס של רשומת-תכנית במרשם.

    Args:
        plan_id: מזהה ה-UUID של הרשומה (מ-plan_list/plan_get)
        status: approved / rejected / pending_review
    """
    if status not in _VALID_STATUS:
        return err("status חייב להיות approved / rejected / pending_review")
    try:
        plan = await db.set_plan_review_status(UUID(plan_id), status)
    except Exception as e:  # noqa: BLE001
        return err(str(e))
    if not plan:
        return err(f"תכנית {plan_id} לא נמצאה.")
    return ok(plan)
