"""Mantara LLM client — thin wrapper that delegates to the active backend.

The backend is selected via MANTARA_BACKEND env var (default: "openai").
See backends/__init__.py for the SchemaGenerator protocol and factory.
"""

from config import SYSTEM_PROMPT_PATH
from models import MantaraSchema
from backends import get_backend


def load_system_prompt() -> str:
    """Load the Mantara system prompt from disk."""
    with open(SYSTEM_PROMPT_PATH) as f:
        return f.read()


# Appended to system prompt so the LLM focuses on JSON quality only.
_JSON_ONLY_ADDENDUM = (
    "\n\n---\n\n"
    "IMPORTANT: For this request, generate ONLY the structured JSON (Part A). "
    "Do NOT generate SQL DDL (Part B) — SQL will be rendered automatically from "
    "your JSON. Focus all effort on producing the most accurate and complete "
    "mantara.schema.v1 JSON with correct submenu IDs, ENUM types, foreign keys, "
    "and column definitions. Include column-level comments for domain context "
    "(units of measurement, value examples, security notes). Include assumptions "
    "and open_questions arrays in the root object.\n\n"
    "CRITICAL RULES:\n"
    "1. Use NUMERIC(12,2) for money/prices/amounts and NUMERIC(10,2) or INT for quantities (NEVER FLOAT for any business value).\n"
    "2. Add CHECK constraints on quantities and amounts.\n"
    "3. EVERY table including line-item tables (order_items, invoice_lines) MUST have submenu_id as the SECOND column.\n"
    "4. Separate master data from assignments (workers table + project_labor, not just labor_management).\n"
    "5. Orders/invoices MUST have line-items tables. Many-to-many relationships MUST have junction tables.\n\n"
    "ENTITY-TO-SUBMENU DECOMPOSITION (prevent common failures):\n"
    "6. Every entity mentioned in the user's input MUST appear as a table — never silently drop entities.\n"
    "7. Target 2-4 submenus per menu. A menu with only 1 submenu should be merged; a menu with 7+ should be split.\n"
    "8. Target 1-3 tables per submenu. A submenu should represent a screen/function, not just a single table.\n"
    "9. Do NOT create a single 'Main' or 'Core' menu that holds all tables. Distribute across domain-specific menus.\n"
    "10. Do NOT put the same table in multiple submenus. Each table belongs to exactly ONE submenu; other submenus use FKs.\n"
    "11. Avoid generic submenu names like 'General', 'Other', 'Misc' — use specific business function names.\n"
    "12. Even simple systems ('todo app') need at least 2 menus and 3 submenus to be a real application.\n\n"
    "THINK STEP BY STEP: Before generating JSON, mentally:\n"
    "  a) List all entities from the input\n"
    "  b) Group entities into domain modules (these become menus)\n"
    "  c) Break each module into user-facing functions (these become submenus)\n"
    "  d) Assign tables to submenus, adding junction/line-item tables where needed\n"
    "  e) Verify every input entity has at least one table — no orphans"
)

_FSD_ADDENDUM = (
    "\n\n"
    "FSD-SPECIFIC INSTRUCTIONS:\n"
    "The input is a Functional Specification Document with pre-extracted analysis context "
    "(marked with === FSD ANALYSIS ===). Use this pre-parsed structure to:\n"
    "- Map DETECTED MODULES to menus (use module names as menu names)\n"
    "- Map DETECTED FEATURES to submenus within their parent modules\n"
    "- Ensure every DETECTED ENTITY has a corresponding table with all listed attributes as columns\n"
    "- Create every DETECTED ENUM CANDIDATE as a proper ENUM type\n"
    "- Implement DETECTED RELATIONSHIPS as foreign keys\n"
    "- Convert DETECTED BUSINESS RULES into CHECK constraints where applicable\n"
)


def generate_schema(user_input: str, model: str | None = None) -> MantaraSchema:
    """Generate a MantaraSchema from user input via the active backend.

    Raises:
        ValueError: If the model refuses the request or returns no output.
        RuntimeError: If all retries are exhausted or backend is misconfigured.
    """
    backend = get_backend()
    system_prompt = load_system_prompt() + _JSON_ONLY_ADDENDUM

    # Add FSD-specific instructions when input contains FSD analysis context
    if "=== FSD ANALYSIS" in user_input:
        system_prompt += _FSD_ADDENDUM

    return backend.generate(system_prompt, user_input, model=model)
