"""OpenAI classification — structured output for folder/tags/title/summary."""

import json
import logging

import httpx

from app.config import OPENAI_API_KEY, OPENAI_MODEL

log = logging.getLogger(__name__)

TAG_DEFINITIONS = {
    "home-assistant": "Home Assistant specific content (dashboards, ESPHome, automations, integrations, Lovelace cards)",
    "server": "Server/infrastructure content (Docker, backups, networking, self-hosted apps, Linux)",
    "kids": "Anything related to children, parenting, or educational content for kids",
    "shopping": "A product page, product review, or specific item you might want to buy (Amazon, stores, book reviews with purchase links). NOT general discussion threads or forums comparing many options.",
    "diy": "Physical hands-on projects around the house, yard, or vehicle — repairs, woodworking, crafts, building things. NOT software, dashboards, or digital projects.",
    "reference": "Lookup info like contacts, sizes, specs, measurements, settings to remember",
    "video": "Video content (YouTube, TikTok, etc)",
    "tutorial": "How-to guides, step-by-step instructions, learning content",
    "books": "Book recommendations, reviews, or reading lists",
    "travel": "Destinations, resorts, hotels, trip ideas, reviews, places to visit",
    "churning": "Credit card points, miles, award travel, hotel loyalty programs, points maximization, sign-up bonuses",
    "lawn-garden": "Lawn care, gardening, yard work, bug spraying, fertilizer, landscaping, plants, outdoor maintenance",
    "piracy": "Anything to do with downloading content like Audiobooks, games",
    "lectures": "Lecture notes, Islamic talks, sermon recordings, religious class notes",
    "3d-printing": "3D printer files (STL), printer mods, filament, slicer settings, 3D printed objects and projects",
    "work": "Work-related content",
    "vanlife": "Van conversion, Promaster van, van build projects, camping in vans, van electrical/solar, van life lifestyle",
    "yusuf": "Personal document belonging to family member Yusuf (look for name in title or content)",
    "madiha": "Personal document belonging to family member Madiha (look for name in title or content)",
    "hafsa": "Personal document belonging to family member Hafsa (look for name in title or content)",
    "mustafa": "Personal document belonging to family member Mustafa (look for name in title or content)",
    "medical": "Medical records, allergy results, prescriptions, lab work, vaccination records, doctor notes",
    "legal": "Birth certificates, passports, IDs, citizenship papers, contracts, legal agreements",
    "vehicle": "Car registration, license plates, insurance cards, vehicle titles, maintenance records",
    "insurance": "Insurance policies, insurance cards, coverage documents, claims",
    "financial": "Tax documents, bank statements, pay stubs, loan papers, credit reports",
    "homeschool": "Homeschooling resources, curriculum, lesson plans, educational materials for teaching kids at home, school projects, science experiments",
}


def build_system_prompt(folders: list[str], tags: list[str]) -> str:
    tag_defs = "\n".join(
        f"  - '{t}': {TAG_DEFINITIONS[t]}" if t in TAG_DEFINITIONS else f"  - '{t}'"
        for t in tags
    )
    return f"""You are a classification engine for a personal "second brain" knowledge management system.

Given an item (URL, note, document, or file), you must return structured JSON with:
- folder: exactly 1 from this list: {json.dumps(folders)}
- tags: ONLY from this predefined list. Do NOT create any new tags outside this list. If no tags fit, return an empty array.
- title: a concise, normalized title in Title Case with spaces (max 80 chars, e.g. 'Machine Learning', 'Web Development')
- summary: a 1-2 sentence summary of the content (for links/documents only)
- corrected_text: for NOTES ONLY — return the original note text with spelling/grammar fixed. Keep the original meaning, tone, and structure. Only fix typos and obvious errors. Return empty string for non-notes.
- confidence: a float 0.0-1.0 indicating how confident you are

Tag definitions (only assign tags that STRONGLY match the content):
{tag_defs}

Rules:
- NEVER invent folders or tags not in the lists above
- Only assign tags that STRONGLY match the content. 1-2 tags is perfectly fine.
- Do NOT pad with extra tags just to reach a target number. If only one tag fits, only use one.
- If NO tags fit the content, return an empty tags array.
- Name tags: 'yusuf', 'madiha', 'hafsa', or 'mustafa' ONLY when the content is a personal document belonging to that family member (look for their name in the title or content)
- NEVER skip classification
- NEVER return freeform text outside the schema
- For notes: do NOT summarize. Keep the original text. Only fix spelling.
- For notes: the summary field should be a very short 5-10 word description, not a rewrite.
- Always return valid JSON matching the schema exactly"""


def build_response_schema(folders: list[str], tags: list[str]) -> dict:
    return {
    "type": "json_schema",
    "json_schema": {
        "name": "classification",
        "strict": True,
        "schema": {
            "type": "object",
            "properties": {
                "folder": {"type": "string", "enum": folders},
                "tags": {
                    "type": "array",
                    "items": {"type": "string", "enum": tags},
                    "minItems": 0,
                    "maxItems": 3,
                },
                "title": {"type": "string"},
                "summary": {"type": "string"},
                "corrected_text": {"type": "string"},
                "confidence": {"type": "number"},
            },
            "required": ["folder", "tags", "title", "summary", "corrected_text", "confidence"],
            "additionalProperties": False,
        },
    },
}


def build_user_prompt(item_type: str, url: str | None, title: str | None, text: str | None) -> str:
    parts = [f"Item type: {item_type}"]
    if url:
        parts.append(f"URL: {url}")
    if title:
        parts.append(f"Original title: {title}")
    if text:
        # Truncate to ~4000 chars for context window efficiency
        truncated = text[:4000]
        parts.append(f"Content:\n{truncated}")
    return "\n\n".join(parts)


async def classify_item(
    item_type: str,
    url: str | None = None,
    title: str | None = None,
    text: str | None = None,
    folders: list[str] | None = None,
    tags: list[str] | None = None,
    retries: int = 2,
) -> dict:
    """Call OpenAI to classify an item. Returns dict with folder, tags, title, summary, confidence."""
    from app.config import FOLDERS, TAGS
    folders = folders or FOLDERS
    tags = tags or TAGS

    if not OPENAI_API_KEY:
        log.warning("No OPENAI_API_KEY set, returning defaults")
        return {
            "folder": "Home",
            "tags": ["reference"],
            "title": title or "Untitled",
            "summary": "No AI classification available",
            "confidence": 0.0,
        }

    user_msg = build_user_prompt(item_type, url, title, text)
    system_prompt = build_system_prompt(folders, tags)
    response_schema = build_response_schema(folders, tags)

    for attempt in range(retries + 1):
        try:
            async with httpx.AsyncClient(timeout=30) as client:
                resp = await client.post(
                    "https://api.openai.com/v1/chat/completions",
                    headers={"Authorization": f"Bearer {OPENAI_API_KEY}"},
                    json={
                        "model": OPENAI_MODEL,
                        "messages": [
                            {"role": "system", "content": system_prompt},
                            {"role": "user", "content": user_msg},
                        ],
                        "response_format": response_schema,
                        "temperature": 0.2,
                    },
                )
                resp.raise_for_status()
                data = resp.json()
                content = data["choices"][0]["message"]["content"]
                result = json.loads(content)

                # Validate folder and tags are in allowed sets
                if result["folder"] not in folders:
                    result["folder"] = folders[0] if folders else "Home"
                result["tags"] = [t for t in result["tags"] if t in tags][:3]

                return result

        except Exception as e:
            log.error(f"Classification attempt {attempt + 1} failed: {e}")
            if attempt == retries:
                return {
                    "folder": "Home",
                    "tags": ["reference"],
                    "title": title or "Untitled",
                    "summary": f"Classification failed: {e}",
                    "confidence": 0.0,
                }
