import json
import os

import httpx
from openai import AsyncOpenAI

# ---------------------------------------------------------------------------
# Demo fixture — returned when LEADSCLEAN_DEMO=1 is set.
# Lets reviewers and new users see the output schema without an API key.
# ---------------------------------------------------------------------------
_DEMO_FIXTURE = {
    "_demo": True,
    "company_name": "Acme Hotels Group",
    "core_business_summary": "Boutique hotel chain with 12 properties across Europe.",
    "product_category_match": (
        "Strong match — hotel groups purchase furniture in bulk for room refits and new openings."
    ),
    "recent_company_trigger": (
        "Announced expansion to 3 new cities in Q1 2026, adding 400+ rooms across the portfolio."
    ),
    "inferred_business_need": (
        "Bulk furnishing (beds, sofas) for new hotel rooms on tight fit-out timelines."
    ),
    "icebreaker_hook_business": (
        "Running 12 properties across Europe is impressive — furnishing them at scale is exactly where we help."
    ),
    "icebreaker_hook_news": (
        "Saw the Q1 expansion news — we help hotel groups source wholesale beds and sofas fast when timelines are tight."
    ),
    "data_provenance": {
        "source_url": "https://acmehotels.com",
        "source_type": "public_website",
        "collection_method": "jina_reader_public_fetch",
        "contains_pii": False,
        "gdpr_basis": "legitimate_interest",
        "gdpr_notes": (
            "Extracted solely from publicly available company web pages. "
            "No personal data collected. Compliant with GDPR Art. 6(1)(f)."
        ),
    },
}

SYSTEM_PROMPT_TEMPLATE = """
You are an elite B2B Sales Intelligence Agent. Your primary function is to analyze raw, unstructured text scraped from target company websites and extract highly accurate, structured commercial signals.
STRICT FACTUALITY: You must extract information strictly based on the provided text. DO NOT hallucinate. If a specific piece of information cannot be found, you MUST output null for that field.
Seller context: {seller_context}
You MUST respond ONLY with a valid JSON object matching this exact schema:
{{
  "company_name": "String",
  "core_business_summary": "String (Max 15 words)",
  "product_category_match": "String or null — does this company likely need what the seller offers? Explain briefly.",
  "recent_company_trigger": "String or null — any recent news, expansion, hiring surge, or event that signals a buying opportunity.",
  "inferred_business_need": "String or null — based on their business model, what specific need aligns with the seller's offering?",
  "icebreaker_hook_business": "String — a concise, personalized opening line referencing their core business.",
  "icebreaker_hook_news": "String or null — a concise opening line referencing a recent trigger or news, if found."
}}
"""

DEFAULT_SELLER_CONTEXT = (
    "We supply wholesale furniture (sofas and beds, spot inventory) "
    "to B2B buyers such as hotels, retailers, and interior design firms."
)

_GDPR_NOTES = (
    "Extracted solely from publicly available company web pages. "
    "No personal data collected. Compliant with GDPR Art. 6(1)(f)."
)


def _build_provenance(url: str) -> dict:
    return {
        "source_url": url,
        "source_type": "public_website",
        "collection_method": "jina_reader_public_fetch",
        "contains_pii": False,
        "gdpr_basis": "legitimate_interest",
        "gdpr_notes": _GDPR_NOTES,
    }


# ---------------------------------------------------------------------------
# LLM provider dispatch — provider is inferred from the model name prefix:
#   gpt-* / o1-* / o3-*  →  OpenAI          (OPENAI_API_KEY)
#   claude-*              →  Anthropic        (ANTHROPIC_API_KEY)
#   qwen-*                →  Alibaba DashScope (DASHSCOPE_API_KEY)
#   abab* / minimax-*     →  MiniMax          (MINIMAX_API_KEY)
# ---------------------------------------------------------------------------

_OPENAI_COMPAT_PROVIDERS = {
    # prefix → (base_url, env_var, supports_json_mode)
    "qwen": (
        "https://dashscope.aliyuncs.com/compatible-mode/v1",
        "DASHSCOPE_API_KEY",
        True,
    ),
    "abab": (
        "https://api.minimax.chat/v1",
        "MINIMAX_API_KEY",
        False,  # MiniMax does not guarantee json_object mode on all models
    ),
    "minimax-": (
        "https://api.minimax.chat/v1",
        "MINIMAX_API_KEY",
        False,
    ),
}


async def _call_openai_compat(
    system_prompt: str,
    user_content: str,
    model: str,
    base_url: str | None,
    env_var: str,
    json_mode: bool,
) -> str:
    api_key = os.getenv(env_var)
    if not api_key:
        raise EnvironmentError(f"{env_var} is not configured.")

    client_kwargs: dict = {"api_key": api_key}
    if base_url:
        client_kwargs["base_url"] = base_url

    client = AsyncOpenAI(**client_kwargs)
    create_kwargs: dict = {
        "model": model,
        "messages": [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_content},
        ],
    }
    if json_mode:
        create_kwargs["response_format"] = {"type": "json_object"}

    completion = await client.chat.completions.create(**create_kwargs)
    return completion.choices[0].message.content


async def _call_anthropic(system_prompt: str, user_content: str, model: str) -> str:
    from anthropic import AsyncAnthropic  # imported lazily — only needed for Claude models

    api_key = os.getenv("ANTHROPIC_API_KEY")
    if not api_key:
        raise EnvironmentError("ANTHROPIC_API_KEY is not configured.")

    client = AsyncAnthropic(api_key=api_key)
    message = await client.messages.create(
        model=model,
        max_tokens=1024,
        system=system_prompt,
        messages=[{"role": "user", "content": user_content}],
    )
    return message.content[0].text


async def _call_llm(system_prompt: str, user_content: str, model: str) -> str:
    """Dispatch to the correct LLM provider based on the model name prefix."""
    if model.startswith("claude-"):
        return await _call_anthropic(system_prompt, user_content, model)

    for prefix, (base_url, env_var, json_mode) in _OPENAI_COMPAT_PROVIDERS.items():
        if model.startswith(prefix):
            return await _call_openai_compat(
                system_prompt, user_content, model, base_url, env_var, json_mode
            )

    # Default: OpenAI (gpt-*, o1-*, o3-*, etc.)
    return await _call_openai_compat(
        system_prompt, user_content, model,
        base_url=None, env_var="OPENAI_API_KEY", json_mode=True,
    )


async def fetch_page_content(url: str) -> str:
    """Fetch clean Markdown content for a URL via Jina Reader."""
    jina_url = f"https://r.jina.ai/{url}"
    async with httpx.AsyncClient(timeout=30.0) as client:
        response = await client.get(jina_url)
        response.raise_for_status()
    content = response.text
    if not content.strip():
        raise ValueError("No content could be extracted from the provided URL.")
    return content


async def extract_lead_intelligence(
    url: str,
    seller_context: str | None = None,
    model: str = "gpt-4o-mini",
) -> dict:
    """
    Fetch a company website and return structured B2B lead intelligence.

    Returns a dict with keys:
    - company_name
    - core_business_summary
    - product_category_match
    - recent_company_trigger
    - inferred_business_need
    - icebreaker_hook_business
    - icebreaker_hook_news
    - data_provenance  (GDPR / source metadata)
    """
    if os.getenv("LEADSCLEAN_DEMO"):
        return _DEMO_FIXTURE

    markdown_content = await fetch_page_content(url)

    resolved_seller_context = seller_context or DEFAULT_SELLER_CONTEXT
    system_prompt = SYSTEM_PROMPT_TEMPLATE.format(seller_context=resolved_seller_context)
    user_content = (
        "Analyze the following website content and extract lead intelligence:\n\n"
        + markdown_content
    )

    raw = await _call_llm(system_prompt, user_content, model)
    result = json.loads(raw)
    result["data_provenance"] = _build_provenance(url)
    return result
