"""
Vision + Yield landing generation via internal LLM gateway.

Outputs MUST be strict JSON to support caching + UI rendering.
"""

from __future__ import annotations

import json
from typing import Any

from pydantic import BaseModel, Field, ValidationError, conint

from app.config import get_settings
from app.services.llm_gateway import chat_completions


settings = get_settings()


VISION_PROMPT_VERSION = "v1"
YIELD_LANDING_PROMPT_VERSION = "v1"


class VisionResult(BaseModel):
    business_concept: str = Field(..., min_length=10, max_length=240)
    industry_vertical: str = Field(..., min_length=2, max_length=60)
    buyer_persona: str = Field(..., min_length=5, max_length=120)
    cold_email_subject: str = Field(..., min_length=5, max_length=120)
    cold_email_body: str = Field(..., min_length=20, max_length=800)
    monetization_idea: str = Field(..., min_length=10, max_length=240)
    radio_test_score: conint(ge=1, le=10)  # type: ignore[valid-type]
    reasoning: str = Field(..., min_length=20, max_length=800)


class YieldLandingConfig(BaseModel):
    template: str = Field(..., min_length=2, max_length=50)  # e.g. "nature", "commerce", "tech"
    headline: str = Field(..., min_length=10, max_length=180)
    seo_intro: str = Field(..., min_length=80, max_length=800)
    cta_label: str = Field(..., min_length=4, max_length=60)
    niche: str = Field(..., min_length=2, max_length=60)
    color_scheme: str = Field(..., min_length=2, max_length=30)


def _extract_first_json_object(text: str) -> str:
    """
    Extract the first {...} JSON object from text.
    We do NOT generate fallback content; if parsing fails, caller must raise.
    """
    s = (text or "").strip()
    if not s:
        raise ValueError("Empty LLM response")
    if s.startswith("{") and s.endswith("}"):
        return s
    start = s.find("{")
    end = s.rfind("}")
    if start == -1 or end == -1 or end <= start:
        raise ValueError("LLM response is not JSON")
    return s[start : end + 1]


async def generate_vision(domain: str) -> tuple[VisionResult, str]:
    """
    Returns (VisionResult, model_used).
    """
    model = settings.llm_default_model
    system = (
        "You are the Pounce AI, a domain intelligence engine.\n"
        "You must respond with STRICT JSON only. No markdown. No commentary.\n"
        "Language: English.\n"
        "If a field is unknown, make a best-effort realistic assumption.\n"
    )
    user = (
        f"Analyze domain '{domain}'.\n"
        "Act as a VC + domain broker.\n"
        "Create a realistic business concept and a buyer/outreach angle.\n"
        "Output STRICT JSON with exactly these keys:\n"
        "{\n"
        '  "business_concept": "...",\n'
        '  "industry_vertical": "...",\n'
        '  "buyer_persona": "...",\n'
        '  "cold_email_subject": "...",\n'
        '  "cold_email_body": "...",\n'
        '  "monetization_idea": "...",\n'
        '  "radio_test_score": 1,\n'
        '  "reasoning": "..."\n'
        "}\n"
    )

    payload: dict[str, Any] = {
        "model": model,
        "messages": [
            {"role": "system", "content": system},
            {"role": "user", "content": user},
        ],
        "temperature": 0.6,
        "stream": False,
    }
    res = await chat_completions(payload)
    content = (
        res.get("choices", [{}])[0]
        .get("message", {})
        .get("content", "")
    )
    json_str = _extract_first_json_object(str(content))
    try:
        data = json.loads(json_str)
    except Exception as e:
        raise ValueError(f"Failed to parse LLM JSON: {e}") from e
    try:
        return VisionResult.model_validate(data), model
    except ValidationError as e:
        raise ValueError(f"LLM JSON schema mismatch: {e}") from e


async def generate_yield_landing(domain: str) -> tuple[YieldLandingConfig, str]:
    """
    Returns (YieldLandingConfig, model_used).
    """
    model = settings.llm_default_model
    system = (
        "You are the Pounce AI, a domain monetization engine.\n"
        "You must respond with STRICT JSON only. No markdown. No commentary.\n"
        "Language: English.\n"
        "Write helpful, non-spammy copy. Avoid medical/legal claims.\n"
    )
    user = (
        f"Analyze domain '{domain}'.\n"
        "Goal: create a minimal SEO-friendly landing page plan that can route visitors to an affiliate offer.\n"
        "Output STRICT JSON with exactly these keys:\n"
        "{\n"
        '  "template": "tech|commerce|finance|nature|local|generic",\n'
        '  "headline": "...",\n'
        '  "seo_intro": "...",\n'
        '  "cta_label": "...",\n'
        '  "niche": "...",\n'
        '  "color_scheme": "..." \n'
        "}\n"
        "Keep seo_intro 120-220 words.\n"
    )

    payload: dict[str, Any] = {
        "model": model,
        "messages": [
            {"role": "system", "content": system},
            {"role": "user", "content": user},
        ],
        "temperature": 0.5,
        "stream": False,
    }
    res = await chat_completions(payload)
    content = (
        res.get("choices", [{}])[0]
        .get("message", {})
        .get("content", "")
    )
    json_str = _extract_first_json_object(str(content))
    try:
        data = json.loads(json_str)
    except Exception as e:
        raise ValueError(f"Failed to parse LLM JSON: {e}") from e
    try:
        return YieldLandingConfig.model_validate(data), model
    except ValidationError as e:
        raise ValueError(f"LLM JSON schema mismatch: {e}") from e

